def fill(self, optionpath, system): """Fill a solver class with data describing a system of forms using libspud, the given optionpath and the system its based on.""" self.name = libspud.get_option(optionpath+"/name") newoptionpath = optionpath+"/type" self.type = libspud.get_option(newoptionpath+"/name") if libspud.have_option(newoptionpath+"/preamble"): self.preamble = libspud.get_option(newoptionpath+"/preamble")+os.linesep self.form_names = [] self.forms = [] self.form_symbols = [] self.form_ranks = [] self.fill_subforms(newoptionpath) prefix = system.name+"_"+self.name+"_" self.fill_solverforms(newoptionpath, prefix=prefix) self.form_representation = libspud.get_option(newoptionpath+"/form_representation/name") if libspud.have_option(newoptionpath+"/quadrature_degree"): self.quadrature_degree = libspud.get_option(newoptionpath+"/quadrature_degree") self.quadrature_rule = libspud.get_option(newoptionpath+"/quadrature_rule/name") self.system = system
def __init__(self, option_path): print option_path self.name = libspud.get_option(option_path + "/name") self.surface_ids = libspud.get_option(option_path + "/surface_ids") self.type = libspud.get_option(option_path + "/type/name") if (self.type == "dirichlet"): self.weak = libspud.have_option(option_path + "/type::%s/apply_weakly" % self.type) self.value = [] R = ["x", "y", "z"] for r in R: if (libspud.have_option( option_path + "/type::%s/align_bc_with_cartesian/%s_component" % (self.type, r))): c = libspud.get_child_name( option_path + "/type::%s/align_bc_with_cartesian/%s_component/" % (self.type), 1) self.value.append( libspud.get_option( option_path + "/type::%s/align_bc_with_cartesian/%s_component/%s" % (self.type, r, c))) else: self.value.append(None) print self.value else: self.weak = None self.value = [None, None, None]
def fill(self, optionpath, system): """Fill a solver class with data describing a system of forms using libspud, the given optionpath and the system its based on.""" self.name = libspud.get_option(optionpath + "/name") newoptionpath = optionpath + "/type" self.type = libspud.get_option(newoptionpath + "/name") if libspud.have_option(newoptionpath + "/preamble"): self.preamble = libspud.get_option(newoptionpath + "/preamble") + os.linesep self.form_names = [] self.forms = [] self.form_symbols = [] self.form_ranks = [] self.fill_subforms(newoptionpath) prefix = system.name + "_" + self.name + "_" self.fill_solverforms(newoptionpath, prefix=prefix) self.form_representation = libspud.get_option( newoptionpath + "/form_representation/name") if libspud.have_option(newoptionpath + "/quadrature_degree"): self.quadrature_degree = libspud.get_option(newoptionpath + "/quadrature_degree") self.quadrature_rule = libspud.get_option(newoptionpath + "/quadrature_rule/name") self.system = system
def get_dirichlet_boundary_conditions(self): """ Create and return all the strong Dirichlet boundary conditions for the Velocity and FreeSurfacePerturbation fields """ # Is the Velocity field represented by a discontinous function space? dg = (self.W.sub(0).ufl_element().family() == "Discontinuous Lagrange") LOG.info("Preparing strong Dirichlet boundary conditions...") bcs = [] bc_expressions = [] for i in range(0, libspud.option_count("/system/core_fields/vector_field::Velocity/boundary_condition")): if(libspud.have_option("/system/core_fields/vector_field::Velocity/boundary_condition[%d]/type::dirichlet" % i) and not libspud.have_option("/system/core_fields/vector_field::Velocity/boundary_condition[%d]/type::dirichlet/apply_weakly" % i)): expr = ExpressionFromOptions(path = ("/system/core_fields/vector_field::Velocity/boundary_condition[%d]/type::dirichlet" % i), t=0).get_expression() # Surface IDs on the domain boundary surface_ids = libspud.get_option("/system/core_fields/vector_field::Velocity/boundary_condition[%d]/surface_ids" % i) method = ("geometric" if dg else "topological") bc = DirichletBC(self.W.sub(0), expr, surface_ids, method=method) bcs.append(bc) bc_expressions.append(expr) LOG.debug("Applying Velocity BC #%d strongly to surface IDs: %s" % (i, surface_ids)) for i in range(0, libspud.option_count("/system/core_fields/scalar_field::FreeSurfacePerturbation/boundary_condition/type::dirichlet")): if(libspud.have_option("/system/core_fields/scalar_field::FreeSurfacePerturbation/boundary_condition[%d]/type::dirichlet" % i) and not(libspud.have_option("/system/core_fields/scalar_field::FreeSurfacePerturbation/boundary_condition[%d]/type::dirichlet/apply_weakly" % i))): expr = ExpressionFromOptions(path = ("/system/core_fields/scalar_field::FreeSurfacePerturbation/boundary_condition[%d]/type::dirichlet" % i), t=0).get_expression() # Surface IDs on the domain boundary surface_ids = libspud.get_option("/system/core_fields/scalar_field::FreeSurfacePerturbation/boundary_condition[%d]/surface_ids" % i) method = ("geometric" if dg else "topological") bc = DirichletBC(self.W.sub(1), expr, surface_ids, method=method) bcs.append(bc) bc_expressions.append(expr) LOG.debug("Applying FreeSurfacePerturbation BC #%d strongly to surface IDs: %s" % (i, surface_ids)) return bcs, bc_expressions
def __init__(self, path, t=None): """ Retrieve the expression's value from the options file. :param str path: The path to the expression's definition in the options file. :param float t: The current time. """ try: if(libspud.have_option(path + "/constant")): self.val = libspud.get_option(path + "/constant") self.type = "constant" elif(libspud.have_option(path + "/python")): v = libspud.get_option(path + "/python") self.type = "python" exec v # Make the 'val' function that the user has defined available for calling. self.val = val self.t = t elif(libspud.have_option(path + "/cpp")): # For C++ expressions. self.type = "cpp" v = libspud.get_option(path + "/cpp") exec v self.val = val self.t = t else: raise ValueError("Unknown expression type.") except ValueError as e: LOG.exception(e) sys.exit() return
def __init__(self, option_path, index): # Name self.name = libspud.get_option(option_path + "/mesh[%d]/name" % index) # Degree if (libspud.have_option( option_path + "/mesh[%d]/from_mesh/mesh_shape/polynomial_degree" % index)): self.degree = libspud.get_option( option_path + "/mesh[%d]/from_mesh/mesh_shape/polynomial_degree" % index) else: self.degree = 1 # Family if (libspud.have_option(option_path + "/mesh[%d]/from_mesh/mesh_continuity" % index)): if (libspud.get_option(option_path + "/mesh[%d]/from_mesh/mesh_continuity" % index) == "continuous"): self.family = "Continuous Lagrange" else: self.family = "Discontinuous Lagrange" else: self.family = "Continuous Lagrange"
def get_inlets(self): """ Wrap the inlet data into a class """ inlets = [] options_base = '/embedded_models/particle_model/inlet' for _ in range(libspud.option_count(options_base)): val = None options_key = options_base +'[%s]'%_ surface_ids = libspud.get_option(options_key+'/surface_ids') insertion_rate = libspud.get_option(options_key+'/insertion_rate') if libspud.have_option(options_key+'/particle_velocity/constant'): rvel = libspud.get_option(options_key+'/particle_velocity/constant') velocity = lambda x, t: rvel elif libspud.have_option(options_key+'/particle_velocity/fluid_velocity'): velocity = None else: exec(libspud.get_option(options_key+'/particle_velocity/python')) in globals(), locals() velocity = val if libspud.have_option(options_key+'/probability_density_function/constant'): rpdf = libspud.get_option(options_key+'/probability_density_function/constant') pdf = lambda x, t: rpdf elif libspud.have_option(options_key+'/probability_density_function/fluid_velocity'): pdf = None else: exec(libspud.get_option(options_key+'/probability_density_function/python')) in globals(), locals() pdf = val inlets.append(Inlet(surface_ids, insertion_rate, velocity, pdf)) return inlets
def get_mesh(self, path): """ Create or load a mesh, given a configuration specified in the simulation configuration file. :param str path: The path to the mesh file. :returns: A Mesh object. """ LOG.info("Creating/loading mesh...") dimension = self.options["dimension"] try: # Unit mesh whose vertex coordinates lie in the range [0, 1] along all axes. if (libspud.have_option("/geometry/mesh/unit_mesh")): number_of_nodes = libspud.get_option( "/geometry/mesh/unit_mesh/number_of_nodes") if (dimension == 1): mesh = UnitIntervalMesh(number_of_nodes[0]) elif (dimension == 2): mesh = UnitSquareMesh(number_of_nodes[0], number_of_nodes[1]) elif (dimension == 3): mesh = UnitCubeMesh(number_of_nodes[0], number_of_nodes[1], number_of_nodes[2]) else: raise ValueError("Unsupported dimension.") # Interval mesh whose vertex coordinates lie in the range [0, L]. elif (libspud.have_option("/geometry/mesh/interval_mesh")): L = libspud.get_option("/geometry/mesh/interval_mesh/length") n = libspud.get_option( "/geometry/mesh/interval_mesh/number_of_cells") mesh = IntervalMesh(n, L) # A user-defined mesh file (currently only supports Gmsh format). elif (libspud.have_option("/geometry/mesh/from_file")): absolute_path_to_config = os.path.dirname( os.path.abspath(path)) # This is the path relative to the directory where the configuration file is stored. relative_path_to_mesh = libspud.get_option( "/geometry/mesh/from_file/relative_path") absolute_path_to_mesh = os.path.join(absolute_path_to_config, relative_path_to_mesh) if (not os.path.exists(absolute_path_to_mesh)): raise ValueError( "The path to the mesh file '%s' does not exist." % absolute_path_to_mesh) else: mesh = Mesh(absolute_path_to_mesh) # Unknown mesh format. else: raise ValueError("Unsupported input mesh type.") except ValueError as e: LOG.exception(e) sys.exit() return mesh
def pre_init(model, xml_path): # load options file libspud.load_options(xml_path) # model name model.project_name = libspud.get_option('project_name') # mesh options model.ele_count = get_optional('mesh/element_count', default=20) # time options option_path = 'time_options/time_discretisation::' if libspud.have_option(option_path + 'runge_kutta'): model.time_discretise = time_discretisation.runge_kutta elif libspud.have_option(option_path + 'crank_nicholson'): model.time_discretise = time_discretisation.crank_nicholson elif libspud.have_option(option_path + 'explicit'): model.time_discretise = time_discretisation.explicit elif libspud.have_option(option_path + 'implicit'): model.time_discretise = time_discretisation.implicit else: raise Exception('unrecognised time discretisation in options file') if libspud.have_option('time_options/finish_time'): model.finish_time = libspud.get_option('time_options/finish_time') model.tol = None elif libspud.have_option('time_options/steady_state_tolerance'): model.tol = libspud.get_option('time_options/steady_state_tolerance') model.finish_time = None else: raise Exception('unrecognised finishing criteria') # spatial_discretisation if libspud.have_option('spatial_discretiation/discretisation::continuous'): model.disc = 'CG' elif libspud.have_option( 'spatial_discretisation/discretisation::discontinuous'): model.disc = 'DG' model.slope_limit = libspud.have_option( 'spatial_discretisation/discretisation/slope_limit') else: raise Exception('unrecognised spatial discretisation in options file') model.degree = get_optional('spatial_discretisation/polynomial_degree', default=1) # tests if libspud.have_option('testing/test::mms'): option_path = 'testing/test::mms/source_terms/' model.mms = True model.S_e = (read_ic(option_path + 'momentum_source', default=None), read_ic(option_path + 'height_source', default=None), read_ic(option_path + 'volume_fraction_source', default=None), read_ic(option_path + 'deposit_depth_source', default=None)) else: model.mms = False
def get_mesh(self, path): """ Create or load a mesh, given a configuration specified in the simulation configuration file. :param str path: The path to the mesh file. :returns: A Mesh object. """ LOG.info("Creating/loading mesh...") dimension = self.options["dimension"] try: # Unit mesh whose vertex coordinates lie in the range [0, 1] along all axes. if(libspud.have_option("/geometry/mesh/unit_mesh")): number_of_nodes = libspud.get_option("/geometry/mesh/unit_mesh/number_of_nodes") if(dimension == 1): mesh = UnitIntervalMesh(number_of_nodes[0]) elif(dimension == 2): mesh = UnitSquareMesh(number_of_nodes[0], number_of_nodes[1]) elif(dimension == 3): mesh = UnitCubeMesh(number_of_nodes[0], number_of_nodes[1], number_of_nodes[2]) else: raise ValueError("Unsupported dimension.") # Interval mesh whose vertex coordinates lie in the range [0, L]. elif(libspud.have_option("/geometry/mesh/interval_mesh")): L = libspud.get_option("/geometry/mesh/interval_mesh/length") n = libspud.get_option("/geometry/mesh/interval_mesh/number_of_cells") mesh = IntervalMesh(n, L) # A user-defined mesh file (currently only supports Gmsh format). elif(libspud.have_option("/geometry/mesh/from_file")): absolute_path_to_config = os.path.dirname(os.path.abspath(path)) # This is the path relative to the directory where the configuration file is stored. relative_path_to_mesh = libspud.get_option("/geometry/mesh/from_file/relative_path") absolute_path_to_mesh = os.path.join(absolute_path_to_config, relative_path_to_mesh) if(not os.path.exists(absolute_path_to_mesh)): raise ValueError("The path to the mesh file '%s' does not exist." % absolute_path_to_mesh) else: mesh = Mesh(absolute_path_to_mesh) # Unknown mesh format. else: raise ValueError("Unsupported input mesh type.") except ValueError as e: LOG.exception(e) sys.exit() return mesh
def fill(self, optionpath, name, function): """Fill a cpp expression class with data describing that expression using libspud, the given optionpath and the function its based on.""" self.name = name self.members = libspud.get_option(optionpath + "/cpp/members") self.initfunc = libspud.get_option(optionpath + "/cpp/initialization") self.evalfunc = libspud.get_option(optionpath + "/cpp/eval") self.function = function if libspud.have_option(optionpath + "/cpp/include"): self.include = libspud.get_option(optionpath + "/cpp/include") self.basetype = libspud.get_option(optionpath + "/type") if self.basetype == "initial_condition": self.nametype = "IC" elif self.basetype == "value": self.nametype = "Value" elif self.basetype == "boundary_condition": self.nametype = "BC" else: print self.basetype print "Unknown type." sys.exit(1) rank = libspud.get_option(optionpath + "/cpp/rank") if rank == "0": # for consistency with other parts of the code convert this to a human parseable string self.rank = "Scalar" elif rank == "1": self.rank = "Vector" elif rank == "2": self.rank = "Tensor" else: print rank print "Unknown rank." sys.exit(1)
def __init__(self, base_option_path, mesh): """ Create an array of turbines. :param str base_option_path: The top-most level of the turbine options in the simulation's configuration/options file. :param mesh: The Mesh object. :returns: None """ fs = FunctionSpace(mesh, "CG", 1) turbine_type = libspud.get_option(base_option_path + "/array/turbine_type/name") turbine_coords = eval(libspud.get_option(base_option_path + "/array/turbine_coordinates")) turbine_radius = eval(libspud.get_option(base_option_path + "/array/turbine_radius")) K = libspud.get_option(base_option_path + "/array/scalar_field::TurbineDragCoefficient/value/constant") self.drag = Function(fs).interpolate(Expression("0")) for coords in turbine_coords: # For each coordinate tuple in the list, create a new turbine. # FIXME: This assumes that all turbines are of the same type. try: if(turbine_type == "bump"): turbine = BumpTurbine(K=K, coords=coords, r=turbine_radius) elif(turbine_type == "tophat"): turbine = TopHatTurbine(K=K, coords=coords, r=turbine_radius) else: raise ValueError("Unknown turbine type '%s'." % turbine_type) except ValueError as e: LOG.exception(e) sys.exit() self.drag += Function(fs).interpolate(turbine) LOG.info("Added %s turbine at %s..." % (turbine_type, coords)) self.optimise = libspud.have_option(base_option_path + "/optimise") return
def get_outlet_ids(self): """ interogate the model specific options """ options_base = '/embedded_models/particle_model/outlet_ids/surface_ids' if libspud.have_option(options_base): return libspud.get_option(options_base) #otherwise return None
def get_option(pclass, key, default=None): """Get option from key.""" result = default if libspud.have_option('/'.join((options_base, pclass, key))): result = libspud.get_option('/'.join((options_base, pclass, key))) return result
def fill(self): """Fill a bucket class with data describing a set of mixedfunctionspace systems using libspud, the given optionpath.""" self.meshes = {} # loop over the meshes in the options tree for i in range(libspud.option_count("/geometry/mesh")): mesh_optionpath = "/geometry/mesh["+`i`+"]" mesh_name = libspud.get_option(mesh_optionpath+"/name") self.meshes[mesh_name] = libspud.get_option(mesh_optionpath+"/source/cell") visualization_optionpath = "/io/visualization/element" self.viselementfamily = libspud.get_option(visualization_optionpath+"/family") self.viselementdegree = libspud.get_option(visualization_optionpath+"/degree") parameters_optionpath = "/global_parameters/ufl" if libspud.have_option(parameters_optionpath): self.parameters = libspud.get_option(parameters_optionpath) self.systems = [] # loop over the systems in the options tree for i in range(libspud.option_count("/system")): system_optionpath = "/system["+`i`+"]" system = buckettools.spud.SpudSystemBucket() # get all the information about this system from the options dictionary system.fill(system_optionpath, self) # let the bucket know about this system self.systems.append(system) # done with this system del system
def fill(self, optionpath, name, function): """Fill a cpp expression class with data describing that expression using libspud, the given optionpath and the function its based on.""" self.name = name self.members = libspud.get_option(optionpath+"/cpp/members") self.initfunc = libspud.get_option(optionpath+"/cpp/initialization") self.evalfunc = libspud.get_option(optionpath+"/cpp/eval") self.function = function if libspud.have_option(optionpath+"/cpp/include"): self.include = libspud.get_option(optionpath+"/cpp/include") self.basetype = libspud.get_option(optionpath+"/type") if self.basetype=="initial_condition": self.nametype = "IC" elif self.basetype=="value": self.nametype = "Value" elif self.basetype=="boundary_condition": self.nametype = "BC" else: print self.basetype print "Unknown type." sys.exit(1) rank = libspud.get_option(optionpath+"/cpp/rank") if rank=="0": # for consistency with other parts of the code convert this to a human parseable string self.rank = "Scalar" elif rank=="1": self.rank = "Vector" elif rank=="2": self.rank = "Tensor" else: print rank print "Unknown rank." sys.exit(1)
def fill_solverforms(self, optionpath, prefix=""): schurpc_optionpath = optionpath+"/composite_type::schur/schur_preconditioner::user" if (libspud.have_option(schurpc_optionpath)): self.fill_subforms(schurpc_optionpath, prefix=prefix) fs_optionpath = optionpath+"/fieldsplit" ls_optionpath = optionpath+"/linear_solver/preconditioner" pc_optionpath = optionpath+"/preconditioner" if (libspud.have_option(fs_optionpath)): for i in range(libspud.option_count(fs_optionpath)): newoptionpath = fs_optionpath+"["+`i`+"]" name = libspud.get_option(newoptionpath+"/name") self.fill_solverforms(newoptionpath+"/linear_solver/preconditioner", prefix=prefix+name+"_") elif (libspud.have_option(ls_optionpath)): self.fill_solverforms(ls_optionpath, prefix=prefix) elif (libspud.have_option(pc_optionpath)): self.fill_solverforms(pc_optionpath, prefix=prefix)
def get_model_option(self, option_name): """ interogate the model specific options """ options_base = '/embedded_models/particle_model/' if libspud.have_option(options_base+option_name): return libspud.get_option(options_base+option_name) #otherwise return None
def __init__(self, option_path, index): # Name self.name = libspud.get_option(option_path + "/mesh[%d]/name" % index) # Degree if(libspud.have_option(option_path + "/mesh[%d]/from_mesh/mesh_shape/polynomial_degree" % index)): self.degree = libspud.get_option(option_path + "/mesh[%d]/from_mesh/mesh_shape/polynomial_degree" % index) else: self.degree = 1 # Family if(libspud.have_option(option_path + "/mesh[%d]/from_mesh/mesh_continuity" % index)): if(libspud.get_option(option_path + "/mesh[%d]/from_mesh/mesh_continuity" % index) == "continuous"): self.family = "Continuous Lagrange" else: self.family = "Discontinuous Lagrange" else: self.family = "Continuous Lagrange"
def get_adapts_at_first_timestep(self): """Return the number of fluidity adapts at first timestep.""" if libspud.have_option( '/mesh_adaptivity/hr_adaptivity/adapt_at_first_timestep/number_of_adapts' ): return libspud.get_option( '/mesh_adaptivity/hr_adaptivity/adapt_at_first_timestep/number_of_adapts' ) # otherwise return 0
def fill_solverforms(self, optionpath, prefix=""): schurpc_optionpath = optionpath + "/composite_type::schur/schur_preconditioner::user" if (libspud.have_option(schurpc_optionpath)): self.fill_subforms(schurpc_optionpath, prefix=prefix) fs_optionpath = optionpath + "/fieldsplit" ls_optionpath = optionpath + "/linear_solver/preconditioner" pc_optionpath = optionpath + "/preconditioner" if (libspud.have_option(fs_optionpath)): for i in range(libspud.option_count(fs_optionpath)): newoptionpath = fs_optionpath + "[" + ` i ` + "]" name = libspud.get_option(newoptionpath + "/name") self.fill_solverforms(newoptionpath + "/linear_solver/preconditioner", prefix=prefix + name + "_") elif (libspud.have_option(ls_optionpath)): self.fill_solverforms(ls_optionpath, prefix=prefix) elif (libspud.have_option(pc_optionpath)): self.fill_solverforms(pc_optionpath, prefix=prefix)
def get_dump_period(self): """Return the dump period and whether this is measured in timesteps.""" if libspud.have_option('/io/dump_period_in_timesteps'): opt_type = libspud.get_child_name('/io/dump_period_in_timesteps', 0) period = libspud.get_option('/io/dump_period_in_timesteps/'+opt_type) return period, True #otherwise opt_type = libspud.get_child_name('/io/dump_period', 0) period = libspud.get_option('/io/dump_period/'+opt_type) return period, False
def __init__(self, option_path): print option_path self.name = libspud.get_option(option_path + "/name") self.surface_ids = libspud.get_option(option_path + "/surface_ids") self.type = libspud.get_option(option_path + "/type/name") if(self.type == "dirichlet"): self.weak = libspud.have_option(option_path + "/type::%s/apply_weakly" % self.type) self.value = [] R = ["x", "y", "z"] for r in R: if(libspud.have_option(option_path + "/type::%s/align_bc_with_cartesian/%s_component" % (self.type, r))): c = libspud.get_child_name(option_path + "/type::%s/align_bc_with_cartesian/%s_component/" % (self.type), 1) self.value.append(libspud.get_option(option_path + "/type::%s/align_bc_with_cartesian/%s_component/%s" % (self.type, r, c))) else: self.value.append(None) print self.value else: self.weak = None self.value = [None, None, None]
def get_rotation(self): """ Return the rotation vector.""" options_base = '/physical_parameters/coriolis/specified_axis' omega = numpy.zeros(3) origin = numpy.zeros(3) if libspud.have_option(options_base): omega[2] = libspud.get_option(options_base+'/rotational_velocity') origin[:self.dimension] = libspud.get_option(options_base+'/point_on_axis') return omega, origin
def __init__(self, path, parent = None): prefix = parent.name if parent else '' self.name = prefix + libspud.get_option(path+'/name') self.rank = int(libspud.get_option(path+'/rank')) if libspud.have_option(path+'/rank') else parent.rank for field_type in [ 'diagnostic', 'prescribed', 'prognostic', 'aliased' ]: if libspud.have_option(path + '/' + field_type): self.field_type = field_type break fieldtypepath = path + '/' + self.field_type # For an aliased field, store material phase and field it is # aliased to, come back later to assign element of the target # field if self.field_type == 'aliased': self.to_phase = libspud.get_option(fieldtypepath + '/material_phase_name') self.to_field = libspud.get_option(fieldtypepath + '/field_name') else: self.mesh = libspud.get_option(fieldtypepath+'/mesh/name') if libspud.have_option(fieldtypepath+'/mesh/name') else parent.mesh if self.field_type == 'prognostic': if libspud.have_option(fieldtypepath + '/equation/name') and libspud.get_option(fieldtypepath + '/equation/name') == 'UFL': self.ufl_equation = libspud.get_option(fieldtypepath + '/equation::UFL')
def get_gravity(self): """ Return the acceleration due to gravity.""" options_base = '/physical_parameters/gravity' magnitude = 0 direction = numpy.zeros(3) self.dimension = libspud.get_option('/geometry/dimension') if libspud.have_option(options_base): magnitude = libspud.get_option(options_base+'/magnitude') direction[:self.dimension] = libspud.get_option(options_base +'/vector_field[0]/prescribed/value[0]/constant') return magnitude*direction
def __init__(self, path): self.path = path self.name = libspud.get_option(path+'/name') # Meshes read from file are alway P1 CG if libspud.have_option(path+'/from_file'): self.shape = 'CG' self.degree = 1 # For derived meshes, check if shape or degree are overridden elif libspud.have_option(path+'/from_mesh'): # Take the inherited options as default basemesh = Mesh('/geometry/'+libspud.get_child_name(path+'/from_mesh',0)) self.shape = basemesh.shape self.degree = basemesh.degree # Override continuity if set if libspud.have_option(path+'/from_mesh/mesh_continuity'): if libspud.get_option(path+'/from_mesh/mesh_continuity') == 'discontinuous': self.shape = 'DG' # Override polynomial degree if set if libspud.have_option(path+'/from_mesh/mesh_shape/polynomial_degree'): self.degree = libspud.get_option(path+'/from_mesh/mesh_shape/polynomial_degree')
def fill(self, optionpath, system, function=None): """Fill a functional class with data describing that functional using libspud, the given optionpath and the system it's based on.""" try: self.name = libspud.get_option(optionpath+"/name") except libspud.SpudKeyError: if function is None: self.name = "" else: self.name = function.name self.symbol = libspud.get_option(optionpath+"/ufl_symbol").split("\n")[0] self.form = libspud.get_option(optionpath)+"\n" self.system = system self.function = function if libspud.have_option(optionpath+"/quadrature_degree"): self.quadrature_degree = libspud.get_option(optionpath+"/quadrature_degree") self.quadrature_rule = libspud.get_option(optionpath+"/quadrature_rule/name")
def get_turbine_array(self): """ Create and return an array of turbines, if desired by the user. """ base_option_path = "/system/equations/momentum_equation/turbines" # Parameterise the turbine array. if (libspud.have_option(base_option_path)): array_type = libspud.get_option(base_option_path + "/array/name") try: if (array_type == "individual"): array = IndividualArray(base_option_path, self.mesh) elif (array_type == "continuum"): array = ContinuumArray(base_option_path, self.mesh) else: raise ValueError("Unknown turbine array type.") except ValueError as e: LOG.exception(e) else: array = None return array
def get_turbine_array(self): """ Create and return an array of turbines, if desired by the user. """ base_option_path = "/system/equations/momentum_equation/turbines" # Parameterise the turbine array. if(libspud.have_option(base_option_path)): array_type = libspud.get_option(base_option_path + "/array/name") try: if(array_type == "individual"): array = IndividualArray(base_option_path, self.mesh) elif(array_type == "continuum"): array = ContinuumArray(base_option_path, self.mesh) else: raise ValueError("Unknown turbine array type.") except ValueError as e: LOG.exception(e) else: array = None return array
def __init__(self, base_option_path, mesh): """ Create an array of turbines. :param str base_option_path: The top-most level of the turbine options in the simulation's configuration/options file. :param mesh: The Mesh object. :returns: None """ fs = FunctionSpace(mesh, "CG", 1) self.thrust_coefficient = libspud.get_option(base_option_path + "/array/thrust_coefficient") self.turbine_area = libspud.get_option(base_option_path + "/array/turbine_area") self.minimum_distance = libspud.get_option(base_option_path + "/array/minimum_distance") self.location = libspud.get_option(base_option_path + "/array/location") self.turbine_density = Function(fs, name="TurbineDensity").interpolate(Expression(self.location + "? %f : 0" % self.bounds()[1])) self.optimise = libspud.have_option(base_option_path + "/optimise") return
def __init__(self, base_option_path, mesh): """ Create an array of turbines. :param str base_option_path: The top-most level of the turbine options in the simulation's configuration/options file. :param mesh: The Mesh object. :returns: None """ fs = FunctionSpace(mesh, "CG", 1) turbine_type = libspud.get_option(base_option_path + "/array/turbine_type/name") turbine_coords = eval( libspud.get_option(base_option_path + "/array/turbine_coordinates")) turbine_radius = eval( libspud.get_option(base_option_path + "/array/turbine_radius")) K = libspud.get_option( base_option_path + "/array/scalar_field::TurbineDragCoefficient/value/constant") self.drag = Function(fs).interpolate(Expression("0")) for coords in turbine_coords: # For each coordinate tuple in the list, create a new turbine. # FIXME: This assumes that all turbines are of the same type. try: if (turbine_type == "bump"): turbine = BumpTurbine(K=K, coords=coords, r=turbine_radius) elif (turbine_type == "tophat"): turbine = TopHatTurbine(K=K, coords=coords, r=turbine_radius) else: raise ValueError("Unknown turbine type '%s'." % turbine_type) except ValueError as e: LOG.exception(e) sys.exit() self.drag += Function(fs).interpolate(turbine) LOG.info("Added %s turbine at %s..." % (turbine_type, coords)) self.optimise = libspud.have_option(base_option_path + "/optimise") return
def fill(self, optionpath, system, function=None): """Fill a functional class with data describing that functional using libspud, the given optionpath and the system it's based on.""" try: self.name = libspud.get_option(optionpath + "/name") except libspud.SpudKeyError: if function is None: self.name = "" else: self.name = function.name self.symbol = libspud.get_option(optionpath + "/ufl_symbol").split( os.linesep)[0] self.form = libspud.get_option(optionpath) + os.linesep self.system = system self.function = function self.form_representation = libspud.get_option( optionpath + "/form_representation/name") if libspud.have_option(optionpath + "/quadrature_degree"): self.quadrature_degree = libspud.get_option(optionpath + "/quadrature_degree") self.quadrature_rule = libspud.get_option(optionpath + "/quadrature_rule/name")
def __init__(self, base_option_path, mesh): """ Create an array of turbines. :param str base_option_path: The top-most level of the turbine options in the simulation's configuration/options file. :param mesh: The Mesh object. :returns: None """ fs = FunctionSpace(mesh, "CG", 1) self.thrust_coefficient = libspud.get_option( base_option_path + "/array/thrust_coefficient") self.turbine_area = libspud.get_option(base_option_path + "/array/turbine_area") self.minimum_distance = libspud.get_option(base_option_path + "/array/minimum_distance") self.location = libspud.get_option(base_option_path + "/array/location") self.turbine_density = Function(fs, name="TurbineDensity").interpolate( Expression(self.location + "? %f : 0" % self.bounds()[1])) self.optimise = libspud.have_option(base_option_path + "/optimise") return
def fill(self, optionpath, system, index): """Fill a function class with data describing that function using libspud, the given optionpath and the system its based on.""" self.name = libspud.get_option(optionpath + "/name") self.symbol = libspud.get_option(optionpath + "/ufl_symbol").split( os.linesep)[0] self.system = system self.index = index self.type = libspud.get_option(optionpath + "/type/name") self.rank = libspud.get_option(optionpath + "/type/rank/name") self.family = None self.degree = None self.functional = None if self.type != "Constant": self.family = libspud.get_option(optionpath + "/type/rank/element/family") self.degree = libspud.get_option(optionpath + "/type/rank/element/degree") self.size = None self.shape = None self.symmetry = None if self.rank == "Vector": if libspud.have_option(optionpath + "/type/rank/element/size"): self.size = libspud.get_option(optionpath + "/type/rank/element/size") elif self.rank == "Tensor": if libspud.have_option(optionpath + "/type/rank/element/shape"): self.shape = libspud.get_option(optionpath + "/type/rank/element/shape") if libspud.have_option(optionpath + "/type/rank/element/symmetric"): self.symmetry = True self.enrichment_family = None self.enrichment_degree = None if libspud.have_option(optionpath + "/type/rank/element/enrichment"): self.enrichment_family = libspud.get_option( optionpath + "/type/rank/element/enrichment/element/family") self.enrichment_degree = libspud.get_option( optionpath + "/type/rank/element/enrichment/element/degree") if libspud.have_option(optionpath + "/type/rank/element/quadrature_rule"): self.quadrature_rule = libspud.get_option( optionpath + "/type/rank/element/quadrature_rule/name") # this should be restricted by the schema to Constant coefficients: if libspud.have_option(optionpath + "/type/rank/value/functional"): functional_optionpath = optionpath + "/type/rank/value/functional" functional = buckettools.spud.SpudFunctionalBucket() functional.fill(functional_optionpath, self.system, self) self.functional = functional self.cpp = [] for k in range( libspud.option_count(optionpath + "/type/rank/initial_condition")): cpp_optionpath = optionpath + "/type/rank/initial_condition[" + ` k ` + "]" if libspud.have_option(cpp_optionpath + "/cpp"): cpp_name = libspud.get_option(cpp_optionpath + "/name") cppexpression = buckettools.spud.SpudCppExpressionBucket() # get all the information about this expression from the options dictionary cppexpression.fill(cpp_optionpath, cpp_name, self) # let the field know about this cpp expression self.cpp.append(cppexpression) # done with this expression del cppexpression for j in range( libspud.option_count(optionpath + "/type/rank/boundary_condition")): bc_optionpath = optionpath + "/type/rank/boundary_condition[" + ` j ` + "]" bc_name = libspud.get_option(bc_optionpath + "/name") for k in range( libspud.option_count(bc_optionpath + "/sub_components")): bc_comp_optionpath = bc_optionpath + "/sub_components[" + ` k ` + "]" bc_comp_name = libspud.get_option(bc_comp_optionpath + "/name") cpp_optionpath = bc_comp_optionpath + "/type" if libspud.have_option(cpp_optionpath + "/cpp"): cpp_name = bc_name + bc_comp_name cppexpression = buckettools.spud.SpudCppExpressionBucket() # get all the information about this expression from the options dictionary cppexpression.fill(cpp_optionpath, cpp_name, self) # let the field know about this cpp expression self.cpp.append(cppexpression) # done with this expression del cppexpression for k in range(libspud.option_count(optionpath + "/type/rank/value")): cpp_optionpath = optionpath + "/type/rank/value[" + ` k ` + "]" if libspud.have_option(cpp_optionpath + "/cpp"): cpp_name = libspud.get_option(cpp_optionpath + "/name") cppexpression = buckettools.spud.SpudCppExpressionBucket() # get all the information about this expression from the options dictionary cppexpression.fill(cpp_optionpath, cpp_name, self) # let the field know about this cpp expression self.cpp.append(cppexpression) # done with this expression del cppexpression
def run(self): """ Perform the simulation! """ # Time-stepping parameters and constants LOG.info("Setting up a few constants...") T = self.options["T"] t = self.options["t"] theta = self.options["theta"] dt = self.options["dt"] dimension = self.options["dimension"] g_magnitude = self.options["g_magnitude"] # Get the function spaces U = self.function_spaces["VelocityFunctionSpace"] H = self.function_spaces["FreeSurfaceFunctionSpace"] # Is the Velocity field represented by a discontinous function space? dg = (U.ufl_element().family() == "Discontinuous Lagrange") # Weight u and h by theta to obtain the theta time-stepping scheme. assert(theta >= 0.0 and theta <= 1.0) LOG.info("Time-stepping scheme using theta = %g" % (theta)) u_mid = (1.0 - theta) * self.u0 + theta * self.u h_mid = (1.0 - theta) * self.h0 + theta * self.h # The total height of the free surface. self.h_total = self.h_mean + self.h0 # Non-linear approximation to the velocity u_nl = Function(U).assign(self.u0) # Second-order Adams-Bashforth velocity u_bash = (3.0/2.0)*self.u0 - (1.0/2.0)*self.u00 # Simple P1 function space, to be used in the stabilisation routines (if applicable). P1 = FunctionSpace(self.mesh, "CG", 1) cellsize = CellSize(self.mesh) ########################################################### ################# Tentative velocity step ################# ########################################################### # The collection of all the individual terms in their weak form. LOG.info("Constructing form...") F = 0 # Mass term if(self.options["have_momentum_mass"]): LOG.debug("Momentum equation: Adding mass term...") M_momentum = (1.0/dt)*(inner(self.w, self.u) - inner(self.w, self.u0))*dx F += M_momentum # Append any Expression objects for weak BCs here. weak_bc_expressions = [] # Advection term if(self.options["have_momentum_advection"]): LOG.debug("Momentum equation: Adding advection term...") if(self.options["integrate_advection_term_by_parts"]): outflow = (dot(self.u0, self.n) + abs(dot(self.u0, self.n)))/2.0 A_momentum = -inner(dot(u_nl, grad(self.w)), u_bash)*dx - inner(dot(u_bash, grad(u_nl)), self.w)*dx A_momentum += inner(self.w, outflow*u_mid)*ds if(dg): # Only add interior facet integrals if we are dealing with a discontinous Galerkin discretisation. A_momentum += dot(outflow('+')*u_mid('+') - outflow('-')*u_mid('-'), jump(self.w))*dS else: A_momentum = inner(dot(grad(self.u), u_nl), self.w)*dx F += A_momentum # Viscous stress term. Note that the viscosity is kinematic (not dynamic). if(self.options["have_momentum_stress"]): LOG.debug("Momentum equation: Adding stress term...") viscosity = Function(H) # Background viscosity background_viscosity = Function(H).interpolate(Expression(libspud.get_option("/system/equations/momentum_equation/stress_term/scalar_field::Viscosity/value/constant"))) viscosity.assign(background_viscosity) # Eddy viscosity if(self.options["have_turbulence_parameterisation"]): LOG.debug("Momentum equation: Adding turbulence parameterisation...") base_option_path = "/system/equations/momentum_equation/turbulence_parameterisation" # Large eddy simulation (LES) if(libspud.have_option(base_option_path + "/les")): les = LES(self.mesh, H) density = Constant(1.0) # We divide through by density in the momentum equation, so just set this to 1.0 for now. smagorinsky_coefficient = Constant(libspud.get_option(base_option_path + "/les/smagorinsky/smagorinsky_coefficient")) eddy_viscosity = Function(H) eddy_viscosity_lhs, eddy_viscosity_rhs = les.eddy_viscosity(u_mid, density, smagorinsky_coefficient) eddy_viscosity_problem = LinearVariationalProblem(eddy_viscosity_lhs, eddy_viscosity_rhs, eddy_viscosity, bcs=[]) eddy_viscosity_solver = LinearVariationalSolver(eddy_viscosity_problem) # Add on eddy viscosity viscosity += eddy_viscosity # Stress tensor: tau = grad(u) + transpose(grad(u)) - (2/3)*div(u) if(not dg): # Perform a double dot product of the stress tensor and grad(w). K_momentum = -viscosity*inner(grad(self.u) + grad(self.u).T, grad(self.w))*dx #K_momentum += viscosity*(2.0/3.0)*inner(div(self.u)*Identity(dimension), grad(self.w))*dx else: # Interior penalty method cellsize = Constant(0.2) # In general, we should use CellSize(self.mesh) instead. alpha = 1/cellsize # Penalty parameter. K_momentum = -viscosity('+')*inner(grad(u_mid), grad(self.w))*dx for dim in range(self.options["dimension"]): K_momentum += -viscosity('+')*(alpha('+')/cellsize('+'))*dot(jump(self.w[dim], self.n), jump(u_mid[dim], self.n))*dS K_momentum += viscosity('+')*dot(avg(grad(self.w[dim])), jump(u_mid[dim], self.n))*dS + viscosity('+')*dot(jump(self.w[dim], self.n), avg(grad(u_mid[dim])))*dS F -= K_momentum # Negative sign here because we are bringing the stress term over from the RHS. # The gradient of the height of the free surface, h LOG.debug("Momentum equation: Adding gradient term...") C_momentum = -g_magnitude*inner(self.w, grad(self.h0))*dx F -= C_momentum # Quadratic drag term in the momentum equation if(self.options["have_drag"]): LOG.debug("Momentum equation: Adding drag term...") base_option_path = "/system/equations/momentum_equation/drag_term" # Get the bottom drag/friction coefficient. LOG.debug("Momentum equation: Adding bottom drag contribution...") bottom_drag = ExpressionFromOptions(path=base_option_path+"/scalar_field::BottomDragCoefficient/value", t=t).get_expression() bottom_drag = Function(H).interpolate(bottom_drag) # Add on the turbine drag, if provided. self.array = None # Magnitude of the velocity field magnitude = sqrt(dot(self.u0, self.u0)) # Form the drag term array = sw.get_turbine_array() if(array): LOG.debug("Momentum equation: Adding turbine drag contribution...") drag_coefficient = bottom_drag + array.turbine_drag() else: drag_coefficient = bottom_drag D_momentum = -inner(self.w, (drag_coefficient*magnitude/self.h_total)*self.u)*dx F -= D_momentum # Add in any source terms if(self.options["have_momentum_source"]): LOG.debug("Momentum equation: Adding source term...") momentum_source_expression = ExpressionFromOptions(path = "/system/equations/momentum_equation/source_term/vector_field::Source/value", t=t).get_expression() momentum_source_function = Function(U) F -= inner(self.w, momentum_source_function.interpolate(momentum_source_expression))*dx # Add in any SU stabilisation if(self.options["have_su_stabilisation"]): LOG.debug("Momentum equation: Adding streamline-upwind stabilisation term...") stabilisation = Stabilisation(self.mesh, P1, cellsize) magnitude = magnitude_vector(self.u0, P1) # Bound the values for the magnitude below by 1.0e-9 for numerical stability reasons. u_nodes = magnitude.vector() near_zero = numpy.array([1.0e-9 for i in range(len(u_nodes))]) u_nodes.set_local(numpy.maximum(u_nodes.array(), near_zero)) diffusivity = ExpressionFromOptions(path = "/system/equations/momentum_equation/stress_term/scalar_field::Viscosity/value", t=self.options["t"]).get_expression() diffusivity = Function(H).interpolate(diffusivity) # Background viscosity grid_pe = grid_peclet_number(diffusivity, magnitude, P1, cellsize) # Bound the values for grid_pe below by 1.0e-9 for numerical stability reasons. grid_pe_nodes = grid_pe.vector() values = numpy.array([1.0e-9 for i in range(len(grid_pe_nodes))]) grid_pe_nodes.set_local(numpy.maximum(grid_pe_nodes.array(), values)) F += stabilisation.streamline_upwind(self.w, self.u0, magnitude, grid_pe) LOG.info("Form construction complete.") ########################################################## ################ Pressure correction step ################ ########################################################## u_tent = Function(U) u_tent_nl = theta*u_tent + (1.0-theta)*self.u0 F_h_corr = inner(self.v, (self.h - self.h0))*dx \ + g_magnitude*(dt**2)*(theta**2)*self.h_total*inner(grad(self.v), grad(self.h - self.h0))*dx \ + dt*self.v*div(self.h_total*u_tent_nl)*dx ########################################################## ################ Velocity correction step ################ ########################################################## h1 = Function(H) u1 = Function(U) F_u_corr = (1.0/dt)*inner(self.w, self.u - u_tent)*dx + g_magnitude*theta*inner(self.w, grad(h1 - self.h0))*dx LOG.info("Applying strong Dirichlet boundary conditions...") # Get all the Dirichlet boundary conditions for the Velocity field bcs_u = []; bcs_u2 = [] bcs_h = [] bc_expressions = [] for i in range(0, libspud.option_count("/system/core_fields/vector_field::Velocity/boundary_condition")): if(libspud.have_option("/system/core_fields/vector_field::Velocity/boundary_condition[%d]/type::dirichlet" % i) and not libspud.have_option("/system/core_fields/vector_field::Velocity/boundary_condition[%d]/type::dirichlet/apply_weakly" % i)): expr = ExpressionFromOptions(path = ("/system/core_fields/vector_field::Velocity/boundary_condition[%d]/type::dirichlet" % i), t=t).get_expression() # Surface IDs on the domain boundary surface_ids = libspud.get_option("/system/core_fields/vector_field::Velocity/boundary_condition[%d]/surface_ids" % i) method = ("geometric" if dg else "topological") bc = DirichletBC(U, expr, surface_ids, method=method) bcs_u.append(bc) bc_expressions.append(expr) LOG.debug("Applying Velocity BC #%d strongly to surface IDs: %s" % (i, surface_ids)) for i in range(0, libspud.option_count("/system/core_fields/vector_field::Velocity/boundary_condition")): if(libspud.have_option("/system/core_fields/vector_field::Velocity/boundary_condition[%d]/type::dirichlet" % i) and not libspud.have_option("/system/core_fields/vector_field::Velocity/boundary_condition[%d]/type::dirichlet/apply_weakly" % i)): expr = ExpressionFromOptions(path = ("/system/core_fields/vector_field::Velocity/boundary_condition[%d]/type::dirichlet" % i), t=t).get_expression() # Surface IDs on the domain boundary surface_ids = libspud.get_option("/system/core_fields/vector_field::Velocity/boundary_condition[%d]/surface_ids" % i) method = ("geometric" if dg else "topological") bc = DirichletBC(U, expr, surface_ids, method=method) bcs_u2.append(bc) bc_expressions.append(expr) LOG.debug("Applying Velocity BC #%d strongly to surface IDs: %s" % (i, surface_ids)) for i in range(0, libspud.option_count("/system/core_fields/scalar_field::FreeSurfacePerturbation/boundary_condition/type::dirichlet")): if(libspud.have_option("/system/core_fields/scalar_field::FreeSurfacePerturbation/boundary_condition[%d]/type::dirichlet" % i) and not(libspud.have_option("/system/core_fields/scalar_field::FreeSurfacePerturbation/boundary_condition[%d]/type::dirichlet/apply_weakly" % i))): expr = ExpressionFromOptions(path = ("/system/core_fields/scalar_field::FreeSurfacePerturbation/boundary_condition[%d]/type::dirichlet" % i), t=t).get_expression() # Surface IDs on the domain boundary surface_ids = libspud.get_option("/system/core_fields/scalar_field::FreeSurfacePerturbation/boundary_condition[%d]/surface_ids" % i) method = ("geometric" if dg else "topological") bc = DirichletBC(H, expr, surface_ids, method=method) bcs_h.append(bc) bc_expressions.append(expr) LOG.debug("Applying FreeSurfacePerturbation BC #%d strongly to surface IDs: %s" % (i, surface_ids)) # Prepare solver_parameters dictionary LOG.debug("Defining solver_parameters dictionary...") solver_parameters = {'ksp_monitor': True, 'ksp_view': False, 'pc_view': False, 'snes_type': 'ksponly', 'ksp_max_it':10000} # NOTE: use 'snes_type': 'newtonls' for production runs. # KSP (iterative solver) options solver_parameters["ksp_type"] = libspud.get_option("/system/solver/iterative_method/name") solver_parameters["ksp_rtol"] = libspud.get_option("/system/solver/relative_error") solver_parameters['ksp_converged_reason'] = True solver_parameters['ksp_monitor_true_residual'] = True # Preconditioner options solver_parameters["pc_type"] = libspud.get_option("/system/solver/preconditioner/name") # Fieldsplit sub-options if(solver_parameters["pc_type"] == "fieldsplit"): LOG.debug("Setting up the fieldsplit preconditioner...") solver_parameters["pc_fieldsplit_type"] = libspud.get_option("/system/solver/preconditioner::fieldsplit/type/name") if(solver_parameters["pc_fieldsplit_type"] == "schur"): solver_parameters["pc_fieldsplit_schur_fact_type"] = libspud.get_option("/system/solver/preconditioner::fieldsplit/type::schur/fact_type/name") solver_parameters["fieldsplit_0_ksp_type"] = libspud.get_option("/system/solver/preconditioner::fieldsplit/block_0_ksp_type/iterative_method/name") solver_parameters["fieldsplit_1_ksp_type"] = libspud.get_option("/system/solver/preconditioner::fieldsplit/block_1_ksp_type/iterative_method/name") if(libspud.get_option("/system/solver/preconditioner::fieldsplit/block_0_pc_type/preconditioner/name") != "ilu"): solver_parameters["fieldsplit_0_pc_type"] = libspud.get_option("/system/solver/preconditioner::fieldsplit/block_0_pc_type/preconditioner/name") solver_parameters["fieldsplit_1_pc_type"] = libspud.get_option("/system/solver/preconditioner::fieldsplit/block_1_pc_type/preconditioner/name") # Enable inner iteration monitors. solver_parameters["fieldsplit_0_ksp_monitor"] = True solver_parameters["fieldsplit_1_ksp_monitor"] = True solver_parameters["fieldsplit_0_pc_factor_shift_type"] = 'INBLOCKS' solver_parameters["fieldsplit_1_pc_factor_shift_type"] = 'INBLOCKS' # Construct the solver objects problem_tent = LinearVariationalProblem(lhs(F), rhs(F), u_tent, bcs=bcs_u) solver_tent = LinearVariationalSolver(problem_tent, solver_parameters={'ksp_monitor': False, 'ksp_view': False, 'pc_view': False, 'pc_type': 'sor', 'ksp_type': 'gmres', 'ksp_rtol': 1.0e-7}) problem_h_corr = LinearVariationalProblem(lhs(F_h_corr), rhs(F_h_corr), h1, bcs=bcs_h) solver_h_corr = LinearVariationalSolver(problem_h_corr, solver_parameters={'ksp_monitor': False, 'ksp_view': False, 'pc_view': False, 'pc_type': 'sor', 'ksp_type': 'gmres', 'ksp_rtol': 1.0e-7}) problem_u_corr = LinearVariationalProblem(lhs(F_u_corr), rhs(F_u_corr), u1, bcs=bcs_u2) solver_u_corr = LinearVariationalSolver(problem_u_corr, solver_parameters={'ksp_monitor': False, 'ksp_view': False, 'pc_view': False, 'pc_type': 'sor', 'ksp_type': 'gmres', 'ksp_rtol': 1.0e-7}) t += dt iterations_since_dump = 1 iterations_since_checkpoint = 1 # PETSc solver run-times from petsc4py import PETSc main_solver_stage = PETSc.Log.Stage('Main block-coupled system solve') total_solver_time = 0.0 # The time-stepping loop LOG.info("Entering the time-stepping loop...") EPSILON = 1.0e-14 while t <= T + EPSILON: # A small value EPSILON is added here in case of round-off error. LOG.info("t = %g" % t) while True: ## Update any time-dependent Functions and Expressions. # Re-compute the velocity magnitude and grid Peclet number fields. if(self.options["have_su_stabilisation"]): magnitude.assign(magnitude_vector(self.u0, P1)) # Bound the values for the magnitude below by 1.0e-9 for numerical stability reasons. u_nodes = magnitude.vector() near_zero = numpy.array([1.0e-9 for i in range(len(u_nodes))]) u_nodes.set_local(numpy.maximum(u_nodes.array(), near_zero)) grid_pe.assign(grid_peclet_number(diffusivity, magnitude, P1, cellsize)) # Bound the values for grid_pe below by 1.0e-9 for numerical stability reasons. grid_pe_nodes = grid_pe.vector() values = numpy.array([1.0e-9 for i in range(len(grid_pe_nodes))]) grid_pe_nodes.set_local(numpy.maximum(grid_pe_nodes.array(), values)) if(self.options["have_turbulence_parameterisation"]): eddy_viscosity_solver.solve() viscosity.assign(background_viscosity + eddy_viscosity) # Time-dependent source terms if(self.options["have_momentum_source"]): momentum_source_expression.t = t momentum_source_function.interpolate(momentum_source_expression) if(self.options["have_continuity_source"]): continuity_source_expression.t = t continuity_source_function.interpolate(continuity_source_expression) # Update any time-varying DirichletBC objects. for expr in bc_expressions: expr.t = t for expr in weak_bc_expressions: expr.t = t # Solve the system of equations! start_solver_time = mpi4py.MPI.Wtime() main_solver_stage.push() LOG.debug("Solving the system of equations...") solver_tent.solve() solver_h_corr.solve() solver_u_corr.solve() main_solver_stage.pop() end_solver_time = mpi4py.MPI.Wtime() total_solver_time += (end_solver_time - start_solver_time) # Move to next time step if(steady_state(u1, u_nl, 1e-7)): break u_nl.assign(u1) self.u00.assign(self.u0) self.u0.assign(u1) self.h0.assign(h1) t += dt iterations_since_dump += 1 iterations_since_checkpoint += 1 LOG.debug("Moving to next time level...") # Write the solution to file. if((self.options["dump_period"] is not None) and (dt*iterations_since_dump >= self.options["dump_period"])): LOG.debug("Writing data to file...") self.output_functions["Velocity"].assign(u1) self.output_files["Velocity"] << self.output_functions["Velocity"] self.output_functions["FreeSurfacePerturbation"].assign(h1) self.output_files["FreeSurfacePerturbation"] << self.output_functions["FreeSurfacePerturbation"] iterations_since_dump = 0 # Reset the counter. # Print out the total power generated by turbines. if(self.options["have_drag"] and self.array is not None): LOG.info("Power = %.2f" % self.array.power(u1, density=1000)) # Checkpointing if((self.options["checkpoint_period"] is not None) and (dt*iterations_since_checkpoint >= self.options["checkpoint_period"])): LOG.debug("Writing checkpoint data to file...") self.solution.dat.save("checkpoint") iterations_since_checkpoint = 0 # Reset the counter. # Check whether a steady-state has been reached. if(steady_state(u1, self.u0, self.options["steady_state_tolerance"]) and steady_state(h1, self.h0, self.options["steady_state_tolerance"])): LOG.info("Steady-state attained. Exiting the time-stepping loop...") break self.compute_diagnostics() LOG.info("Out of the time-stepping loop.") LOG.debug("Total solver time: %.2f" % (total_solver_time)) return u1, h1
def convert(fluidity_options_file_path, ff_options_file_path): # Read in Fluidity simulation options libspud.clear_options() libspud.load_options(fluidity_options_file_path) # Simulation name simulation_name = libspud.get_option("/simulation_name") # Geometry base = "/geometry" dimension = libspud.get_option(base + "/dimension") mesh_path = libspud.get_option( base + "/mesh::CoordinateMesh/from_file/file_name" ) + ".msh" # FIXME: Always assumes gmsh format. # Function spaces velocity_function_space = FunctionSpace("/geometry", 1) freesurface_function_space = FunctionSpace("/geometry", 2) # Timestepping base = "/timestepping" current_time = libspud.get_option(base + "/current_time") timestep = libspud.get_option(base + "/timestep") finish_time = libspud.get_option(base + "/finish_time") ## Steady-state if (libspud.have_option(base + "/steady_state")): if (libspud.have_option(base + "/steady_state/tolerance")): steady_state = libspud.get_option(base + "/steady_state/tolerance") else: steady_state = 1e-7 else: steady_state = None # I/O base = "/io" dump_format = libspud.get_option(base + "/dump_format") if (libspud.have_option(base + "/dump_period")): dump_period = libspud.get_option(base + "/dump_period/constant") elif (libspud.have_option(base + "/dump_period_in_timesteps")): dump_period = libspud.get_option( base + "/dump_period_in_timesteps/constant") * timestep else: print "Unable to obtain dump_period." sys.exit() # Gravity g_magnitude = libspud.get_option("/physical_parameters/gravity/magnitude") # Velocity field (momentum equation) base = "/material_phase[0]/vector_field::Velocity" ## Depth (free surface mean height) c = libspud.get_child_name( base + "/prognostic/equation::ShallowWater/scalar_field::BottomDepth/prescribed/value::WholeMesh/", 1) depth = libspud.get_option( base + "/prognostic/equation::ShallowWater/scalar_field::BottomDepth/prescribed/value::WholeMesh/%s" % c) ## Bottom drag coefficient if (libspud.have_option(base + "/prognostic/equation::ShallowWater/bottom_drag")): c = libspud.get_child_name( base + "/prognostic/equation::ShallowWater/bottom_drag/scalar_field::BottomDragCoefficient/prescribed/value::WholeMesh/", 1) bottom_drag = libspud.get_option( base + "/prognostic/equation::ShallowWater/bottom_drag/scalar_field::BottomDragCoefficient/prescribed/value::WholeMesh/%s" % c) else: bottom_drag = None ## Viscosity if (libspud.have_option(base + "/prognostic/tensor_field::Viscosity")): viscosity = libspud.get_option( base + "/prognostic/tensor_field::Viscosity/prescribed/value::WholeMesh/anisotropic_symmetric/constant" )[0][0] else: viscosity = None ## Momentum source if (libspud.have_option(base + "/prognostic/vector_field::Source")): c = libspud.get_child_name( base + "/prognostic/vector_field::Source/prescribed/value::WholeMesh/", 1) momentum_source = libspud.get_option( base + "/prognostic/vector_field::Source/prescribed/value::WholeMesh/%s" % c) else: momentum_source = None ## Initial condition if (libspud.have_option(base + "/prognostic/initial_condition::WholeMesh")): c = libspud.get_child_name( base + "/prognostic/initial_condition::WholeMesh/", 1) velocity_initial_condition = libspud.get_option( base + "/prognostic/initial_condition::WholeMesh/%s" % c) else: velocity_initial_condition = 0.0 ## Boundary conditions number_of_bcs = libspud.option_count(base + "/prognostic/boundary_conditions") velocity_bcs = [] for i in range(number_of_bcs): velocity_bcs.append( VelocityBoundaryCondition(base + "/prognostic/boundary_conditions[%d]" % i)) # Pressure field (continuity equation) base = "/material_phase[0]/scalar_field::Pressure" integrate_by_parts = libspud.have_option( base + "/prognostic/spatial_discretisation/continuous_galerkin/integrate_continuity_by_parts" ) ## Initial condition if (libspud.have_option(base + "/prognostic/initial_condition::WholeMesh")): c = libspud.get_child_name( base + "/prognostic/initial_condition::WholeMesh/", 1) pressure_initial_condition = libspud.get_option( base + "/prognostic/initial_condition::WholeMesh/%s" % c) else: pressure_initial_condition = 0.0 ## Boundary conditions number_of_bcs = libspud.option_count(base + "/prognostic/boundary_conditions") pressure_bcs = [] for i in range(number_of_bcs): pressure_bcs.append( PressureBoundaryCondition(base + "/prognostic/boundary_conditions[%d]" % i)) ## Continuity source if (libspud.have_option(base + "/prognostic/scalar_field::Source")): c = libspud.get_child_name( base + "/prognostic/scalar_field::Source/prescribed/value::WholeMesh/", 1) continuity_source = libspud.get_option( base + "/prognostic/scalar_field::Source/prescribed/value::WholeMesh/%s" % c) else: continuity_source = None # Write out to a Firedrake-Fluids simulation configuration file libspud.clear_options() # Create a bare-bones .swml file to add to. f = open(ff_options_file_path, "w") f.write("<?xml version='1.0' encoding='utf-8'?>\n") f.write("<shallow_water_options>\n") f.write("</shallow_water_options>\n") f.close() libspud.load_options(ff_options_file_path) # Simulation name libspud.set_option("/simulation_name", simulation_name) # Geometry base = "/geometry" libspud.set_option(base + "/dimension", dimension) libspud.set_option(base + "/mesh/from_file/relative_path", mesh_path) # Function spaces base = "/function_spaces" libspud.set_option(base + "/function_space::VelocityFunctionSpace/degree", velocity_function_space.degree) libspud.set_option(base + "/function_space::VelocityFunctionSpace/family", velocity_function_space.family) libspud.set_option( base + "/function_space::FreeSurfaceFunctionSpace/degree", freesurface_function_space.degree) libspud.set_option( base + "/function_space::FreeSurfaceFunctionSpace/family", freesurface_function_space.family) # I/O base = "/io" libspud.set_option(base + "/dump_format", dump_format) libspud.set_option(base + "/dump_period", dump_period) # Timestepping base = "/timestepping" print timestep libspud.set_option(base + "/current_time", current_time) try: libspud.set_option(base + "/timestep", timestep) except: pass libspud.set_option(base + "/finish_time", finish_time) ## Steady-state if (steady_state): libspud.set_option(base + "/steady_state/tolerance", steady_state) # Gravity libspud.set_option("/physical_parameters/gravity/magnitude", g_magnitude) # System/Core Fields: Velocity base = "/system/core_fields/vector_field::Velocity" ## Initial condition if (isinstance(velocity_initial_condition, str)): libspud.set_option(base + "/initial_condition/python", velocity_initial_condition) else: libspud.set_option(base + "/initial_condition/constant", velocity_initial_condition) ## Boundary conditions try: for i in range(len(velocity_bcs)): libspud.set_option( base + "/boundary_condition::%s/surface_ids" % velocity_bcs[i].name, velocity_bcs[i].surface_ids) libspud.set_option_attribute( base + "/boundary_condition::%s/type/name" % velocity_bcs[i].name, velocity_bcs[i].type) if (velocity_bcs[i].type == "dirichlet"): if (isinstance(velocity_bcs[i].value, str)): libspud.set_option( base + "/boundary_condition::%s/type::dirichlet/value/python" % velocity_bcs[i].name, velocity_bcs[i].value) else: libspud.set_option( base + "/boundary_condition::%s/type::dirichlet/value/constant" % velocity_bcs[i].name, velocity_bcs[i].value) except: pass # System/Core Fields: FreeSurfacePerturbation base = "/system/core_fields/scalar_field::FreeSurfacePerturbation" #FIXME: Pressure initial and boundary conditions are multiplied by 'g' in Fluidity, but not in Firedrake-Fluids. ## Initial condition if (isinstance(pressure_initial_condition, str)): libspud.set_option(base + "/initial_condition/python", pressure_initial_condition) else: libspud.set_option(base + "/initial_condition/constant", pressure_initial_condition) ## Boundary conditions try: for i in range(len(pressure_bcs)): libspud.set_option( base + "/boundary_condition::%s/surface_ids" % pressure_bcs[i].name, pressure_bcs[i].surface_ids) libspud.set_option( base + "/boundary_condition::%s/type/name" % pressure_bcs[i].name, pressure_bcs[i].type) if (pressure_bcs[i].type == "dirichlet"): if (isinstance(pressure_bcs[i].value, str)): libspud.set_option( base + "/boundary_condition::%s/type::dirichlet/value/python" % pressure_bcs[i].name, pressure_bcs[i].value) else: libspud.set_option( base + "/boundary_condition::%s/type::dirichlet/value/constant" % pressure_bcs[i].name, pressure_bcs[i].value) except: pass # System/Core Fields: FreeSurfaceMean base = "/system/core_fields/scalar_field::FreeSurfaceMean" if (isinstance(depth, str)): libspud.set_option(base + "/value/python", depth) else: libspud.set_option(base + "/value/constant", depth) # Equations: Continuity equation base = "/system/equations/continuity_equation" libspud.set_option(base + "/integrate_by_parts", integrate_by_parts) ## Source term if (continuity_source is not None): if (isinstance(continuity_source, str)): libspud.set_option( base + "/source_term/scalar_field::Source/value/python", continuity_source) else: libspud.set_option( base + "/source_term/scalar_field::Source/value/constant", continuity_source) # Equations: Momentum equation base = "/system/equations/momentum_equation" ## Viscosity if (viscosity is not None): if (isinstance(viscosity, str)): libspud.set_option( base + "/stress_term/scalar_field::Viscosity/value/python", viscosity) else: libspud.set_option( base + "/stress_term/scalar_field::Viscosity/value/constant", viscosity) ## Bottom drag if (bottom_drag is not None): if (isinstance(bottom_drag, str)): libspud.set_option( base + "/drag_term/scalar_field::BottomDragCoefficient/value/python", bottom_drag) else: libspud.set_option( base + "/drag_term/scalar_field::BottomDragCoefficient/value/constant", bottom_drag) ## Source term if (momentum_source is not None): if (isinstance(momentum_source, str)): libspud.set_option( base + "/source_term/vector_field::Source/value/python", momentum_source) else: libspud.set_option( base + "/source_term/vector_field::Source/value/constant", momentum_source) # Write all the applied options to file. libspud.write_options(ff_options_file_path) return
import libspud libspud.load_options('test.flml') #libspud.print_options() assert libspud.get_option('/timestepping/timestep') == 0.025 assert libspud.get_number_of_children('/geometry') == 5 assert libspud.get_child_name('geometry', 0) == "dimension" assert libspud.option_count('/problem_type') == 1 assert libspud.have_option('/problem_type') assert libspud.get_option_type('/geometry/dimension') is int assert libspud.get_option_type('/problem_type') is str assert libspud.get_option_rank('/geometry/dimension') == 0 assert libspud.get_option_rank( '/physical_parameters/gravity/vector_field::GravityDirection/prescribed/value/constant' ) == 1 assert libspud.get_option_shape('/geometry/dimension') == (-1, -1) assert libspud.get_option_shape('/problem_type')[0] > 1 assert libspud.get_option_shape('/problem_type')[1] == -1 assert libspud.get_option('/problem_type') == "multimaterial" assert libspud.get_option('/geometry/dimension') == 2 libspud.set_option('/geometry/dimension', 3) assert libspud.get_option('/geometry/dimension') == 3
def fill(self, optionpath, bucket): """Fill a system class with data describing that system using libspud and the given optionpath.""" self.name = libspud.get_option(optionpath + "/name") self.optionpath = optionpath self.symbol = libspud.get_option(optionpath + "/ufl_symbol").split( os.linesep)[0] self.bucket = bucket self.mesh_name = libspud.get_option(optionpath + "/mesh/name") mesh_optionpath = "/geometry/mesh::" + self.mesh_name self.cell = libspud.get_option(mesh_optionpath + "/source/cell") self.fields = [] for j in range(libspud.option_count(optionpath + "/field")): field_optionpath = optionpath + "/field[" + ` j ` + "]" field = buckettools.spud.SpudFunctionBucket() # get all the information about this field from the options dictionary field.fill(field_optionpath, self, j) # let the system know about this field self.fields.append(field) # remove the local copy of this field del field self.coeffs = [] for j in range(libspud.option_count(optionpath + "/coefficient")): coeff_optionpath = optionpath + "/coefficient[" + ` j ` + "]" coeff = buckettools.spud.SpudFunctionBucket() # get all the information about this coefficient from the options dictionary coeff.fill(coeff_optionpath, self, j) # let the system know about this coefficient self.coeffs.append(coeff) # remove the local copy of this coefficient del coeff self.special_coeffs = [] if libspud.have_option("/timestepping"): coeff_optionpath = "/timestepping/timestep/coefficient::Timestep" coeff = buckettools.spud.SpudFunctionBucket() # get all the information about this coefficient from the options dictionary coeff.fill(coeff_optionpath, self, 0) # let the system know about this coefficient self.special_coeffs.append(coeff) # remove the local copy of this coefficient del coeff self.solvers = [] for j in range(libspud.option_count(optionpath + "/nonlinear_solver")): solver_optionpath = optionpath + "/nonlinear_solver[" + ` j ` + "]" solver = buckettools.spud.SpudSolverBucket() # get all the information about this nonlinear solver from the options dictionary solver.fill(solver_optionpath, self) # let the system know about this solver self.solvers.append(solver) # done with this nonlinear solver del solver self.functionals = [] for j in range(libspud.option_count(optionpath + "/functional")): functional_optionpath = optionpath + "/functional[" + ` j ` + "]" functional = buckettools.spud.SpudFunctionalBucket() # get all the information about this functional from the options dictionary functional.fill(functional_optionpath, self) # let the system know about this functional self.functionals.append(functional) # done with this functional del functional
def run(self, array=None, annotate=False, checkpoint=None): """ Perform the simulation! """ # The solution field defined on the mixed function space solution = Function(self.W, name="Solution", annotate=annotate) # The solution from the previous time-step. At t=0, this holds the initial conditions. solution_old = Function(self.W, name="SolutionOld", annotate=annotate) # Assign the initial condition initial_condition = self.get_initial_condition(checkpoint=checkpoint) solution_old.assign(initial_condition, annotate=annotate) # Get the test functions test_functions = TestFunctions(self.W) w = test_functions[0]; v = test_functions[1] LOG.info("Test functions created.") # These are like the TrialFunctions, but are just regular Functions here because we want to solve a non-linear problem # 'u' and 'h' are the velocity and free surface perturbation, respectively. functions = split(solution) u = functions[0]; h = functions[1] LOG.info("Trial functions created.") functions_old = split(solution_old) u_old = functions_old[0]; h_old = functions_old[1] # Write initial conditions to file LOG.info("Writing initial conditions to file...") self.output_functions["Velocity"].assign(solution_old.split()[0], annotate=False) self.output_files["Velocity"] << self.output_functions["Velocity"] self.output_functions["FreeSurfacePerturbation"].assign(solution_old.split()[1], annotate=False) self.output_files["FreeSurfacePerturbation"] << self.output_functions["FreeSurfacePerturbation"] # Construct the collection of all the individual terms in their weak form. LOG.info("Constructing form...") F = 0 theta = self.options["theta"] dt = self.options["dt"] dimension = self.options["dimension"] g_magnitude = self.options["g_magnitude"] # Is the Velocity field represented by a discontinous function space? dg = (self.W.sub(0).ufl_element().family() == "Discontinuous Lagrange") # Mean free surface height h_mean = Function(self.W.sub(1), name="FreeSurfaceMean", annotate=False) h_mean.interpolate(ExpressionFromOptions(path = "/system/core_fields/scalar_field::FreeSurfaceMean/value").get_expression()) # Weight u and h by theta to obtain the theta time-stepping scheme. assert(theta >= 0.0 and theta <= 1.0) LOG.info("Time-stepping scheme using theta = %g" % (theta)) u_mid = (1.0 - theta) * u_old + theta * u h_mid = (1.0 - theta) * h_old + theta * h # The total height of the free surface. H = h_mean + h # Simple P1 function space, to be used in the stabilisation routines (if applicable). P1 = FunctionSpace(self.mesh, "CG", 1) cellsize = CellSize(self.mesh) # Normal vector to each element facet n = FacetNormal(self.mesh) # Mass term if(self.options["have_momentum_mass"]): LOG.debug("Momentum equation: Adding mass term...") M_momentum = (1.0/dt)*(inner(w, u) - inner(w, u_old))*dx F += M_momentum # Advection term if(self.options["have_momentum_advection"]): LOG.debug("Momentum equation: Adding advection term...") if(self.options["integrate_advection_term_by_parts"]): outflow = (dot(u_mid, n) + abs(dot(u_mid, n)))/2.0 A_momentum = -inner(dot(u_mid, grad(w)), u_mid)*dx - inner(dot(u_mid, grad(u_mid)), w)*dx A_momentum += inner(w, outflow*u_mid)*ds if(dg): # Only add interior facet integrals if we are dealing with a discontinous Galerkin discretisation. A_momentum += dot(outflow('+')*u_mid('+') - outflow('-')*u_mid('-'), jump(w))*dS else: A_momentum = inner(dot(grad(u_mid), u_mid), w)*dx F += A_momentum # Viscous stress term. Note that the viscosity is kinematic (not dynamic). if(self.options["have_momentum_stress"]): LOG.debug("Momentum equation: Adding stress term...") viscosity = Function(self.W.sub(1)) # Background viscosity background_viscosity = Function(self.W.sub(1)).interpolate(Expression(libspud.get_option("/system/equations/momentum_equation/stress_term/scalar_field::Viscosity/value/constant"))) viscosity.assign(background_viscosity) # Eddy viscosity if(self.options["have_turbulence_parameterisation"]): LOG.debug("Momentum equation: Adding turbulence parameterisation...") base_option_path = "/system/equations/momentum_equation/turbulence_parameterisation" # Large eddy simulation (LES) if(libspud.have_option(base_option_path + "/les")): density = Constant(1.0) # We divide through by density in the momentum equation, so just set this to 1.0 for now. smagorinsky_coefficient = Constant(libspud.get_option(base_option_path + "/les/smagorinsky/smagorinsky_coefficient")) les = LES(self.mesh, self.W.sub(1), u_mid, density, smagorinsky_coefficient) # Add on eddy viscosity viscosity += les.eddy_viscosity # Stress tensor: tau = grad(u) + transpose(grad(u)) - (2/3)*div(u) if(not dg): # Perform a double dot product of the stress tensor and grad(w). K_momentum = -viscosity*inner(grad(u_mid) + grad(u_mid).T, grad(w))*dx K_momentum += viscosity*(2.0/3.0)*inner(div(u_mid)*Identity(dimension), grad(w))*dx else: # Interior penalty method cellsize = Constant(0.2) # In general, we should use CellSize(self.mesh) instead. alpha = 1/cellsize # Penalty parameter. K_momentum = -viscosity('+')*inner(grad(u_mid), grad(w))*dx for dim in range(self.options["dimension"]): K_momentum += -viscosity('+')*(alpha('+')/cellsize('+'))*dot(jump(w[dim], n), jump(u_mid[dim], n))*dS K_momentum += viscosity('+')*dot(avg(grad(w[dim])), jump(u_mid[dim], n))*dS + viscosity('+')*dot(jump(w[dim], n), avg(grad(u_mid[dim])))*dS F -= K_momentum # Negative sign here because we are bringing the stress term over from the RHS. # The gradient of the height of the free surface, h LOG.debug("Momentum equation: Adding gradient term...") C_momentum = -g_magnitude*inner(w, grad(h_mid))*dx F -= C_momentum # Quadratic drag term in the momentum equation if(self.options["have_drag"]): LOG.debug("Momentum equation: Adding drag term...") base_option_path = "/system/equations/momentum_equation/drag_term" # Get the bottom drag/friction coefficient. LOG.debug("Momentum equation: Adding bottom drag contribution...") bottom_drag = ExpressionFromOptions(path=base_option_path+"/scalar_field::BottomDragCoefficient/value", t=0).get_expression() bottom_drag = Function(self.W.sub(1)).interpolate(bottom_drag) # Magnitude of the velocity field magnitude = sqrt(dot(u_old, u_old)) # Form the drag term if(array): LOG.debug("Momentum equation: Adding turbine drag contribution...") drag_coefficient = bottom_drag + array.turbine_drag() else: drag_coefficient = bottom_drag D_momentum = -inner(w, (drag_coefficient*magnitude/H)*u_mid)*dx F -= D_momentum # The mass term in the shallow water continuity equation # (i.e. an advection equation for the free surface height, h) if(self.options["have_continuity_mass"]): LOG.debug("Continuity equation: Adding mass term...") M_continuity = (1.0/dt)*(inner(v, h) - inner(v, h_old))*dx F += M_continuity # Append any Expression objects for weak BCs here. weak_bc_expressions = [] # Divergence term in the shallow water continuity equation LOG.debug("Continuity equation: Adding divergence term...") if(self.options["integrate_continuity_equation_by_parts"]): LOG.debug("The divergence term is being integrated by parts.") Ct_continuity = - H*inner(u_mid, grad(v))*dx if(dg): Ct_continuity += inner(jump(v, n), avg(H*u_mid))*dS # Add in the surface integrals, but check to see if any boundary conditions need to be applied weakly here. boundary_markers = self.mesh.exterior_facets.unique_markers for marker in boundary_markers: marker = int(marker) # ds() will not accept markers of type 'numpy.int32', so convert it to type 'int' here. bc_type = None for i in range(0, libspud.option_count("/system/core_fields/vector_field::Velocity/boundary_condition")): bc_path = "/system/core_fields/vector_field::Velocity/boundary_condition[%d]" % i if(not (marker in libspud.get_option(bc_path + "/surface_ids"))): # This BC is not associated with this marker, so skip it. continue # Determine the BC type. if(libspud.have_option(bc_path + "/type::no_normal_flow")): bc_type = "no_normal_flow" elif(libspud.have_option(bc_path + "/type::dirichlet")): if(libspud.have_option(bc_path + "/type::dirichlet/apply_weakly")): bc_type = "weak_dirichlet" else: bc_type = "dirichlet" elif(libspud.have_option(bc_path + "/type::flather")): bc_type = "flather" # Apply the boundary condition... try: LOG.debug("Applying Velocity BC of type '%s' to surface ID %d..." % (bc_type, marker)) if(bc_type == "flather"): # The known exterior value for the Velocity. u_ext = ExpressionFromOptions(path = (bc_path + "/type::flather/exterior_velocity"), t=0).get_expression() Ct_continuity += H*inner(Function(self.W.sub(0)).interpolate(u_ext), n)*v*ds(int(marker)) # The known exterior value for the FreeSurfacePerturbation. h_ext = ExpressionFromOptions(path = (bc_path + "/type::flather/exterior_free_surface_perturbation"), t=0).get_expression() Ct_continuity += H*sqrt(g_magnitude/H)*(h_mid - Function(self.W.sub(1)).interpolate(h_ext))*v*ds(int(marker)) weak_bc_expressions.append(u_ext) weak_bc_expressions.append(h_ext) elif(bc_type == "weak_dirichlet"): u_bdy = ExpressionFromOptions(path = (bc_path + "/type::dirichlet"), t=0).get_expression() Ct_continuity += H*(dot(Function(self.W.sub(0)).interpolate(u_bdy), n))*v*ds(int(marker)) weak_bc_expressions.append(u_bdy) elif(bc_type == "dirichlet"): # Add in the surface integral as it is here. The BC will be applied strongly later using a DirichletBC object. Ct_continuity += H * inner(u_mid, n) * v * ds(int(marker)) elif(bc_type == "no_normal_flow"): # Do nothing here since dot(u, n) is zero. continue else: raise ValueError("Unknown boundary condition type!") except ValueError as e: LOG.exception(e) sys.exit() # If no boundary condition has been applied, include the surface integral as it is. if(bc_type is None): Ct_continuity += H * inner(u_mid, n) * v * ds(int(marker)) else: Ct_continuity = inner(v, div(H*u_mid))*dx F += Ct_continuity # Add in any source terms if(self.options["have_momentum_source"]): LOG.debug("Momentum equation: Adding source term...") momentum_source_expression = ExpressionFromOptions(path = "/system/equations/momentum_equation/source_term/vector_field::Source/value", t=0).get_expression() momentum_source_function = Function(self.W.sub(0), annotate=False) F -= inner(w, momentum_source_function.interpolate(momentum_source_expression))*dx if(self.options["have_continuity_source"]): LOG.debug("Continuity equation: Adding source term...") continuity_source_expression = ExpressionFromOptions(path = "/system/equations/continuity_equation/source_term/scalar_field::Source/value", t=0).get_expression() continuity_source_function = Function(self.W.sub(1), annotate=False) F -= inner(v, continuity_source_function.interpolate(continuity_source_expression))*dx # Add in any SU stabilisation if(self.options["have_su_stabilisation"]): LOG.debug("Momentum equation: Adding streamline-upwind stabilisation term...") stabilisation = Stabilisation(self.mesh, P1, cellsize) magnitude = magnitude_vector(solution_old.split()[0], P1) # Bound the values for the magnitude below by 1.0e-9 for numerical stability reasons. u_nodes = magnitude.vector() near_zero = numpy.array([1.0e-9 for i in range(len(u_nodes))]) u_nodes.set_local(numpy.maximum(u_nodes.array(), near_zero)) diffusivity = ExpressionFromOptions(path = "/system/equations/momentum_equation/stress_term/scalar_field::Viscosity/value", t=self.options["t"]).get_expression() diffusivity = Function(self.W.sub(1)).interpolate(diffusivity) # Background viscosity grid_pe = grid_peclet_number(diffusivity, magnitude, P1, cellsize) # Bound the values for grid_pe below by 1.0e-9 for numerical stability reasons. grid_pe_nodes = grid_pe.vector() values = numpy.array([1.0e-9 for i in range(len(grid_pe_nodes))]) grid_pe_nodes.set_local(numpy.maximum(grid_pe_nodes.array(), values)) F += stabilisation.streamline_upwind(w, u, magnitude, grid_pe) LOG.info("Form construction complete.") bcs, bc_expressions = self.get_dirichlet_boundary_conditions() # Prepare solver_parameters dictionary solver_parameters = self.get_solver_parameters() # Construct the solver objects problem = NonlinearVariationalProblem(F, solution, bcs=bcs) solver = NonlinearVariationalSolver(problem, solver_parameters=solver_parameters) LOG.debug("Variational problem solver created.") # PETSc solver run-times from petsc4py import PETSc main_solver_stage = PETSc.Log.Stage('Main block-coupled system solve') total_solver_time = 0.0 # Time-stepping parameters and constants T = self.options["T"] t = self.options["t"] t += dt iterations_since_dump = 1 iterations_since_checkpoint = 1 # The time-stepping loop LOG.info("Entering the time-stepping loop...") #if annotate: adj_start_timestep(time=t) EPSILON = 1.0e-14 while t <= T + EPSILON: # A small value EPSILON is added here in case of round-off error. LOG.info("t = %g" % t) ## Update any time-dependent Functions and Expressions. # Re-compute the velocity magnitude and grid Peclet number fields. if(self.options["have_su_stabilisation"]): magnitude.assign(magnitude_vector(solution_old.split()[0], P1)) # Bound the values for the magnitude below by 1.0e-9 for numerical stability reasons. u_nodes = magnitude.vector() near_zero = numpy.array([1.0e-9 for i in range(len(u_nodes))]) u_nodes.set_local(numpy.maximum(u_nodes.array(), near_zero)) grid_pe.assign(grid_peclet_number(diffusivity, magnitude, P1, cellsize)) # Bound the values for grid_pe below by 1.0e-9 for numerical stability reasons. grid_pe_nodes = grid_pe.vector() values = numpy.array([1.0e-9 for i in range(len(grid_pe_nodes))]) grid_pe_nodes.set_local(numpy.maximum(grid_pe_nodes.array(), values)) if(self.options["have_turbulence_parameterisation"]): les.solve() # Time-dependent source terms if(self.options["have_momentum_source"]): momentum_source_expression.t = t momentum_source_function.interpolate(momentum_source_expression) if(self.options["have_continuity_source"]): continuity_source_expression.t = t continuity_source_function.interpolate(continuity_source_expression) # Update any time-varying DirichletBC objects. for expr in bc_expressions: expr.t = t for expr in weak_bc_expressions: expr.t = t # Solve the system of equations! start_solver_time = mpi4py.MPI.Wtime() main_solver_stage.push() LOG.debug("Solving the system of equations...") solver.solve(annotate=annotate) main_solver_stage.pop() end_solver_time = mpi4py.MPI.Wtime() total_solver_time += (end_solver_time - start_solver_time) # Write the solution to file. if((self.options["dump_period"] is not None) and (dt*iterations_since_dump >= self.options["dump_period"])): LOG.debug("Writing data to file...") self.output_functions["Velocity"].assign(solution.split()[0], annotate=False) self.output_files["Velocity"] << self.output_functions["Velocity"] self.output_functions["FreeSurfacePerturbation"].assign(solution.split()[1], annotate=False) self.output_files["FreeSurfacePerturbation"] << self.output_functions["FreeSurfacePerturbation"] iterations_since_dump = 0 # Reset the counter. # Print out the total power generated by turbines. if(array): LOG.info("Power = %.2f" % array.power(u, density=1000)) # Checkpointing if((self.options["checkpoint_period"] is not None) and (dt*iterations_since_checkpoint >= self.options["checkpoint_period"])): LOG.debug("Writing checkpoint data to file...") solution.dat.save("checkpoint") iterations_since_checkpoint = 0 # Reset the counter. # Check whether a steady-state has been reached. if(steady_state(solution.split()[0], solution_old.split()[0], self.options["steady_state_tolerance"]) and steady_state(solution.split()[1], solution_old.split()[1], self.options["steady_state_tolerance"])): LOG.info("Steady-state attained. Exiting the time-stepping loop...") break self.compute_diagnostics() # Move to next time step solution_old.assign(solution, annotate=annotate) #array.turbine_drag.assign(project(array.turbine_drag, array.turbine_drag.function_space(), annotate=annotate), annotate=annotate) t += dt #if annotate: adj_inc_timestep(time=t, finished=t>T) iterations_since_dump += 1 iterations_since_checkpoint += 1 LOG.debug("Moving to next time level...") LOG.info("Out of the time-stepping loop.") LOG.debug("Total solver time: %.2f" % (total_solver_time)) return solution
def convert(fluidity_options_file_path, ff_options_file_path): # Read in Fluidity simulation options libspud.clear_options() libspud.load_options(fluidity_options_file_path) # Simulation name simulation_name = libspud.get_option("/simulation_name") # Geometry base = "/geometry" dimension = libspud.get_option(base + "/dimension") mesh_path = libspud.get_option(base + "/mesh::CoordinateMesh/from_file/file_name") + ".msh" # FIXME: Always assumes gmsh format. # Function spaces velocity_function_space = FunctionSpace("/geometry", 1) freesurface_function_space = FunctionSpace("/geometry", 2) # Timestepping base = "/timestepping" current_time = libspud.get_option(base + "/current_time") timestep = libspud.get_option(base + "/timestep") finish_time = libspud.get_option(base + "/finish_time") ## Steady-state if(libspud.have_option(base + "/steady_state")): if(libspud.have_option(base + "/steady_state/tolerance")): steady_state = libspud.get_option(base + "/steady_state/tolerance") else: steady_state = 1e-7 else: steady_state = None # I/O base = "/io" dump_format = libspud.get_option(base + "/dump_format") if(libspud.have_option(base + "/dump_period")): dump_period = libspud.get_option(base + "/dump_period/constant") elif(libspud.have_option(base + "/dump_period_in_timesteps")): dump_period = libspud.get_option(base + "/dump_period_in_timesteps/constant")*timestep else: print "Unable to obtain dump_period." sys.exit() # Gravity g_magnitude = libspud.get_option("/physical_parameters/gravity/magnitude") # Velocity field (momentum equation) base = "/material_phase[0]/vector_field::Velocity" ## Depth (free surface mean height) c = libspud.get_child_name(base + "/prognostic/equation::ShallowWater/scalar_field::BottomDepth/prescribed/value::WholeMesh/", 1) depth = libspud.get_option(base + "/prognostic/equation::ShallowWater/scalar_field::BottomDepth/prescribed/value::WholeMesh/%s" % c) ## Bottom drag coefficient if(libspud.have_option(base + "/prognostic/equation::ShallowWater/bottom_drag")): c = libspud.get_child_name(base + "/prognostic/equation::ShallowWater/bottom_drag/scalar_field::BottomDragCoefficient/prescribed/value::WholeMesh/", 1) bottom_drag = libspud.get_option(base + "/prognostic/equation::ShallowWater/bottom_drag/scalar_field::BottomDragCoefficient/prescribed/value::WholeMesh/%s" % c) else: bottom_drag = None ## Viscosity if(libspud.have_option(base + "/prognostic/tensor_field::Viscosity")): viscosity = libspud.get_option(base + "/prognostic/tensor_field::Viscosity/prescribed/value::WholeMesh/anisotropic_symmetric/constant")[0][0] else: viscosity = None ## Momentum source if(libspud.have_option(base + "/prognostic/vector_field::Source")): c = libspud.get_child_name(base + "/prognostic/vector_field::Source/prescribed/value::WholeMesh/", 1) momentum_source = libspud.get_option(base + "/prognostic/vector_field::Source/prescribed/value::WholeMesh/%s" % c) else: momentum_source = None ## Initial condition if(libspud.have_option(base + "/prognostic/initial_condition::WholeMesh")): c = libspud.get_child_name(base + "/prognostic/initial_condition::WholeMesh/", 1) velocity_initial_condition = libspud.get_option(base + "/prognostic/initial_condition::WholeMesh/%s" % c) else: velocity_initial_condition = 0.0 ## Boundary conditions number_of_bcs = libspud.option_count(base + "/prognostic/boundary_conditions") velocity_bcs = [] for i in range(number_of_bcs): velocity_bcs.append(VelocityBoundaryCondition(base + "/prognostic/boundary_conditions[%d]" % i)) # Pressure field (continuity equation) base = "/material_phase[0]/scalar_field::Pressure" integrate_by_parts = libspud.have_option(base + "/prognostic/spatial_discretisation/continuous_galerkin/integrate_continuity_by_parts") ## Initial condition if(libspud.have_option(base + "/prognostic/initial_condition::WholeMesh")): c = libspud.get_child_name(base + "/prognostic/initial_condition::WholeMesh/", 1) pressure_initial_condition = libspud.get_option(base + "/prognostic/initial_condition::WholeMesh/%s" % c) else: pressure_initial_condition = 0.0 ## Boundary conditions number_of_bcs = libspud.option_count(base + "/prognostic/boundary_conditions") pressure_bcs = [] for i in range(number_of_bcs): pressure_bcs.append(PressureBoundaryCondition(base + "/prognostic/boundary_conditions[%d]" % i)) ## Continuity source if(libspud.have_option(base + "/prognostic/scalar_field::Source")): c = libspud.get_child_name(base + "/prognostic/scalar_field::Source/prescribed/value::WholeMesh/", 1) continuity_source = libspud.get_option(base + "/prognostic/scalar_field::Source/prescribed/value::WholeMesh/%s" % c) else: continuity_source = None # Write out to a Firedrake-Fluids simulation configuration file libspud.clear_options() # Create a bare-bones .swml file to add to. f = open(ff_options_file_path, "w") f.write("<?xml version='1.0' encoding='utf-8'?>\n") f.write("<shallow_water_options>\n") f.write("</shallow_water_options>\n") f.close() libspud.load_options(ff_options_file_path) # Simulation name libspud.set_option("/simulation_name", simulation_name) # Geometry base = "/geometry" libspud.set_option(base + "/dimension", dimension) libspud.set_option(base + "/mesh/from_file/relative_path", mesh_path) # Function spaces base = "/function_spaces" libspud.set_option(base + "/function_space::VelocityFunctionSpace/degree", velocity_function_space.degree) libspud.set_option(base + "/function_space::VelocityFunctionSpace/family", velocity_function_space.family) libspud.set_option(base + "/function_space::FreeSurfaceFunctionSpace/degree", freesurface_function_space.degree) libspud.set_option(base + "/function_space::FreeSurfaceFunctionSpace/family", freesurface_function_space.family) # I/O base = "/io" libspud.set_option(base + "/dump_format", dump_format) libspud.set_option(base + "/dump_period", dump_period) # Timestepping base = "/timestepping" print timestep libspud.set_option(base + "/current_time", current_time) try: libspud.set_option(base + "/timestep", timestep) except: pass libspud.set_option(base + "/finish_time", finish_time) ## Steady-state if(steady_state): libspud.set_option(base + "/steady_state/tolerance", steady_state) # Gravity libspud.set_option("/physical_parameters/gravity/magnitude", g_magnitude) # System/Core Fields: Velocity base = "/system/core_fields/vector_field::Velocity" ## Initial condition if(isinstance(velocity_initial_condition, str)): libspud.set_option(base + "/initial_condition/python", velocity_initial_condition) else: libspud.set_option(base + "/initial_condition/constant", velocity_initial_condition) ## Boundary conditions try: for i in range(len(velocity_bcs)): libspud.set_option(base + "/boundary_condition::%s/surface_ids" % velocity_bcs[i].name, velocity_bcs[i].surface_ids) libspud.set_option_attribute(base + "/boundary_condition::%s/type/name" % velocity_bcs[i].name, velocity_bcs[i].type) if(velocity_bcs[i].type == "dirichlet"): if(isinstance(velocity_bcs[i].value, str)): libspud.set_option(base + "/boundary_condition::%s/type::dirichlet/value/python" % velocity_bcs[i].name, velocity_bcs[i].value) else: libspud.set_option(base + "/boundary_condition::%s/type::dirichlet/value/constant" % velocity_bcs[i].name, velocity_bcs[i].value) except: pass # System/Core Fields: FreeSurfacePerturbation base = "/system/core_fields/scalar_field::FreeSurfacePerturbation" #FIXME: Pressure initial and boundary conditions are multiplied by 'g' in Fluidity, but not in Firedrake-Fluids. ## Initial condition if(isinstance(pressure_initial_condition, str)): libspud.set_option(base + "/initial_condition/python", pressure_initial_condition) else: libspud.set_option(base + "/initial_condition/constant", pressure_initial_condition) ## Boundary conditions try: for i in range(len(pressure_bcs)): libspud.set_option(base + "/boundary_condition::%s/surface_ids" % pressure_bcs[i].name, pressure_bcs[i].surface_ids) libspud.set_option(base + "/boundary_condition::%s/type/name" % pressure_bcs[i].name, pressure_bcs[i].type) if(pressure_bcs[i].type == "dirichlet"): if(isinstance(pressure_bcs[i].value, str)): libspud.set_option(base + "/boundary_condition::%s/type::dirichlet/value/python" % pressure_bcs[i].name, pressure_bcs[i].value) else: libspud.set_option(base + "/boundary_condition::%s/type::dirichlet/value/constant" % pressure_bcs[i].name, pressure_bcs[i].value) except: pass # System/Core Fields: FreeSurfaceMean base = "/system/core_fields/scalar_field::FreeSurfaceMean" if(isinstance(depth, str)): libspud.set_option(base + "/value/python", depth) else: libspud.set_option(base + "/value/constant", depth) # Equations: Continuity equation base = "/system/equations/continuity_equation" libspud.set_option(base + "/integrate_by_parts", integrate_by_parts) ## Source term if(continuity_source is not None): if(isinstance(continuity_source, str)): libspud.set_option(base + "/source_term/scalar_field::Source/value/python", continuity_source) else: libspud.set_option(base + "/source_term/scalar_field::Source/value/constant", continuity_source) # Equations: Momentum equation base = "/system/equations/momentum_equation" ## Viscosity if(viscosity is not None): if(isinstance(viscosity, str)): libspud.set_option(base + "/stress_term/scalar_field::Viscosity/value/python", viscosity) else: libspud.set_option(base + "/stress_term/scalar_field::Viscosity/value/constant", viscosity) ## Bottom drag if(bottom_drag is not None): if(isinstance(bottom_drag, str)): libspud.set_option(base + "/drag_term/scalar_field::BottomDragCoefficient/value/python", bottom_drag) else: libspud.set_option(base + "/drag_term/scalar_field::BottomDragCoefficient/value/constant", bottom_drag) ## Source term if(momentum_source is not None): if(isinstance(momentum_source, str)): libspud.set_option(base + "/source_term/vector_field::Source/value/python", momentum_source) else: libspud.set_option(base + "/source_term/vector_field::Source/value/constant", momentum_source) # Write all the applied options to file. libspud.write_options(ff_options_file_path) return
def populate_options(self): """ Add simulation options related to the shallow water model to a dictionary object. :returns: None """ # A dictionary storing all the options self.options = {} LOG.info("Populating options dictionary...") self.options["simulation_name"] = libspud.get_option("/simulation_name") self.options["dimension"] = libspud.get_option("/geometry/dimension") # Time-stepping parameters self.options["T"] = libspud.get_option("/timestepping/finish_time") self.options["t"] = libspud.get_option("/timestepping/current_time") self.options["dt"] = libspud.get_option("/timestepping/timestep") self.options["theta"] = libspud.get_option("/timestepping/theta") if(libspud.have_option("/timestepping/steady_state")): self.options["steady_state_tolerance"] = libspud.get_option("/timestepping/steady_state/tolerance") else: self.options["steady_state_tolerance"] = -1000 # I/O parameters if(libspud.have_option("/io/dump_period")): self.options["dump_period"] = libspud.get_option("/io/dump_period") else: self.options["dump_period"] = None if(libspud.have_option("/io/checkpoint")): self.options["checkpoint_period"] = libspud.get_option("/io/checkpoint/dump_period") else: self.options["checkpoint_period"] = None # Physical parameters self.options["g_magnitude"] = libspud.get_option("/physical_parameters/gravity/magnitude") # Enable/disable terms in the shallow water equations self.options["have_momentum_mass"] = (not libspud.have_option("/system/equations/momentum_equation/mass_term/exclude_mass_term")) self.options["have_momentum_advection"] = (not libspud.have_option("/system/equations/momentum_equation/advection_term/exclude_advection_term")) self.options["have_momentum_stress"] = libspud.have_option("/system/equations/momentum_equation/stress_term") self.options["have_continuity_mass"] = (not libspud.have_option("/system/equations/continuity_equation/mass_term/exclude_mass_term")) # Source terms for the momentum and continuity equations self.options["have_momentum_source"] = libspud.have_option("/system/equations/momentum_equation/source_term") self.options["have_continuity_source"] = libspud.have_option("/system/equations/continuity_equation/source_term") # Check for any SU stabilisation self.options["have_su_stabilisation"] = libspud.have_option("/system/equations/momentum_equation/spatial_discretisation/continuous_galerkin/stabilisation/streamline_upwind") # Turbulence parameterisation self.options["have_turbulence_parameterisation"] = libspud.have_option("/system/equations/momentum_equation/turbulence_parameterisation") # Drag parameterisation self.options["have_drag"] = libspud.have_option("/system/equations/momentum_equation/drag_term") # Integration by parts self.options["integrate_continuity_equation_by_parts"] = libspud.have_option("/system/equations/continuity_equation/integrate_by_parts") self.options["integrate_advection_term_by_parts"] = libspud.have_option("/system/equations/momentum_equation/advection_term/integrate_by_parts") return
import libspud print libspud.__file__ libspud.load_options('test.flml') libspud.print_options() print libspud.number_of_children('/geometry') print libspud.get_child_name('geometry', 0) print libspud.option_count('/problem_type') print libspud.have_option('/problem_type') print libspud.get_option_type('/geometry/dimension') print libspud.get_option_type('/problem_type') print libspud.get_option_rank('/geometry/dimension') print libspud.get_option_rank('/physical_parameters/gravity/vector_field::GravityDirection/prescribed/value/constant') print libspud.get_option_shape('/geometry/dimension') print libspud.get_option_shape('/problem_type') print libspud.get_option('/problem_type') print libspud.get_option('/geometry/dimension') libspud.set_option('/geometry/dimension', 3) print libspud.get_option('/geometry/dimension') list_path = '/material_phase::Material1/scalar_field::MaterialVolumeFraction/prognostic/boundary_conditions::LetNoOneLeave/surface_ids' print libspud.get_option_shape(list_path) print libspud.get_option_rank(list_path) print libspud.get_option(list_path)
def post_init(model, xml_path): model.start_time = get_optional('time_options/start_time', default=0.0) if libspud.have_option('time_options/adaptive_timestep'): option_path = 'time_options/adaptive_timestep/' model.adapt_timestep = True model.adapt_cfl = project(Constant( libspud.get_option(option_path + 'cfl_criteria')), model.R, name='cfl') else: model.adapt_timestep = False model.adapt_cfl = project(Constant(0.2), model.R, name='cfl') # ts info options if libspud.have_option('output_options/ts_info'): model.ts_info = True else: model.ts_info = False # plotting options option_path = 'output_options/plotting/' if libspud.have_option('output_options/plotting'): model.plot = libspud.get_option(option_path + 'plotting_interval') if libspud.have_option(option_path + 'output::both'): model.show_plot = True model.save_plot = True elif libspud.have_option(option_path + 'output::live_plotting'): model.show_plot = True model.save_plot = False elif libspud.have_option(option_path + 'output::save_plots'): model.show_plot = False model.save_plot = True else: raise Exception('unrecognised plotting output in options file') option_path = option_path + 'dimensionalise_plots/' else: model.plot = None # dimenionalisation model.g = project(Constant( get_optional(option_path + 'g_prime', default=1.0)), model.R, name='g_prime') model.h_0 = project(Constant(get_optional(option_path + 'h_0', default=1.0)), model.R, name='h_0') model.phi_0 = project(Constant( get_optional(option_path + 'phi_0', default=1.0)), model.R, name='phi_0') # non dimensional numbers option_path = 'non_dimensional_numbers/' model.Fr = project(Constant(get_optional(option_path + 'Fr', default=1.19)), model.R, name="Fr") model.beta = project(Constant( get_optional(option_path + 'beta', default=5e-3)), model.R, name="beta") # initial conditions model.form_ic = ( { 'id': 'momentum', 'function': Function(model.V, name='ic_q'), 'test_function': TestFunction(model.V) }, { 'id': 'height', 'function': Function(model.V, name='ic_h'), 'test_function': TestFunction(model.V) }, { 'id': 'volume_fraction', 'function': Function(model.V, name='ic_phi'), 'test_function': TestFunction(model.V) }, { 'id': 'deposit_depth', 'function': Function(model.V, name='ic_phi_d'), 'test_function': TestFunction(model.V) }, { 'id': 'initial_length', 'function': Function(model.R, name='ic_X_n'), 'test_function': TestFunction(model.R) }, { 'id': 'front_velocity', 'function': Function(model.R, name='ic_u_N'), 'test_function': TestFunction(model.R) }, { 'id': 'timestep', 'function': Function(model.R, name='ic_k'), 'test_function': TestFunction(model.R) }, { 'id': 'phi_int', 'function': Function(model.R, name='ic_phi_int'), 'test_function': TestFunction(model.R) }, ) option_path = 'initial_conditions/' var_paths = 'momentum', 'height', 'volume_fraction', 'deposit_depth', \ 'initial_length', 'front_velocity', 'timestep' # form defines ic for i, var_path in enumerate(var_paths): path = option_path + var_path + '/form' if libspud.have_option(path): if libspud.have_option(path + '/additional_form_var'): for j in range( libspud.option_count(path + '/additional_form_var/var')): py_code = libspud.get_option( path + '/additional_form_var/var[%d]' % j) exec py_code py_code = "model.form_ic[%d]['form'] = %s" % ( i, libspud.get_option(path)) exec py_code # expression defined ic model.w_ic_var = '' if (libspud.have_option(option_path + 'variables') and libspud.option_count(option_path + 'variables/var') > 0): n_var = libspud.option_count(option_path + 'variables/var') for i_var in range(n_var): name = libspud.get_child_name(option_path + 'variables/', i_var) var = name.split(':')[-1] code = libspud.get_option('initial_conditions/variables/' + name + '/code') model.w_ic_var = model.w_ic_var + var + ' = ' + code + ', ' ic_exp = (read_ic(option_path + 'momentum', default='0.0'), read_ic(option_path + 'height', default='1.0'), read_ic(option_path + 'volume_fraction', default='1.0'), read_ic(option_path + 'deposit_depth', default='0.0'), read_ic(option_path + 'initial_length', default='1.0'), read_ic(option_path + 'front_velocity', default='1.19'), read_ic(option_path + 'timestep', default='1.0'), '0.0') exp_str = ('model.w_ic_e = Expression(ic_exp, model.W.ufl_element(), %s)' % model.w_ic_var) exec exp_str in globals(), locals()
def read_ic(path, default): if libspud.have_option(path + '/c_string'): return libspud.get_option(path + '/c_string') else: return default
def get_optional(path, default): if libspud.have_option(path): return libspud.get_option(path) else: return default
import libspud libspud.load_options('test.flml') #libspud.print_options() assert libspud.get_option('/timestepping/timestep') == 0.025 assert libspud.get_number_of_children('/geometry') == 5 assert libspud.get_child_name('geometry', 0) == "dimension" assert libspud.option_count('/problem_type') == 1 assert libspud.have_option('/problem_type') assert libspud.get_option_type('/geometry/dimension') is int assert libspud.get_option_type('/problem_type') is str assert libspud.get_option_rank('/geometry/dimension') == 0 assert libspud.get_option_rank('/physical_parameters/gravity/vector_field::GravityDirection/prescribed/value/constant') == 1 assert libspud.get_option_shape('/geometry/dimension') == (-1, -1) assert libspud.get_option_shape('/problem_type')[0] > 1 assert libspud.get_option_shape('/problem_type')[1] == -1 assert libspud.get_option('/problem_type') == "multimaterial" assert libspud.get_option('/geometry/dimension') == 2 libspud.set_option('/geometry/dimension', 3) assert libspud.get_option('/geometry/dimension') == 3
def data_assimilation(opal_options): global Model_updated, iter_count # functions used within data_assimilation: J() and gradJ() def J(v): global Model_updated, iter_count iter_count = iter_count + 1 vT = np.transpose(v) vTv = np.dot(vT,v) Vv = np.dot(V,v) HVv = np.dot(H,Vv) # we need the model results - check if these are already available, if not, run the forward model with Vv as the input if Model_updated: print "in J(): using pre-exiting forward model model solution" Model_updated = False else: print "in J(): updating the forward model solution" # prepare directory and input files for forward model input_file_name = prepare_inputs_for_forward_model(k) # modify initial condition of tracer field = modify_initial_conditions_at_tk(k,Vv) # run forward model run_forward_model_tk(k,opal_options.executable,input_file_name) Model_updated = True # retrieve the forward model results, MVv path_to_vtu_file = str(k) + '/2d_canyon_1.vtu' vtu_data = vtktools.vtu(path_to_vtu_file) MVv = vtu_data.GetScalarField(field) # print "J(): MVv[0:10]", MVv[0:10] ##MVv = np.dot(M,Vv) HMVv = np.dot(H,MVv) Jmis = np.subtract(HVv,d) JmisM = np.subtract(HMVv,d) invR = np.linalg.inv(R) JmisT = np.transpose(Jmis) JmisMT = np.transpose(JmisM) RJmis = np.dot(invR,JmisT) RJmisM = np.dot(invR,JmisMT) J1 = np.dot(Jmis,RJmis) JM1 = np.dot(JmisM,RJmisM) Jv = (vTv + J1 + JM1) / 2 return Jv ############################################### ####### GRADIENT OF J ######## ############################################### def gradJ(v): global Model_updated Vv = np.dot(V,v) HVv = np.dot(H,Vv) # CODE COPIED FROM J() ########################################### # we need the model results - check if these are already available, # if not, run the forward model with Vv as the input if Model_updated: print "in gradJ(): using pre-exiting forward model model solution" Model_updated = False else: print "in gradJ(): updating the forward model solution" # prepare directory and input files for forward model input_file_name = prepare_inputs_for_forward_model(k) # modify initial condition of tracer field = modify_initial_conditions_at_tk(k,Vv) # run forward model run_forward_model_tk(k,opal_options.executable,input_file_name) Model_updated = True # END OF CODE COPIED FROM J() ########################################### # MVv = np.dot(M,Vv) # retrieve the forward model results, MVv path_to_vtu_file = str(k) + '/2d_canyon_1.vtu' vtu_data = vtktools.vtu(path_to_vtu_file) MVv = vtu_data.GetScalarField('Tracer') #vtu_data.GetScalarField(field) # print "gradJ: MVv[0:10]", MVv[0:10] HMVv = np.dot(H,MVv) Jmis = np.subtract(HVv,d) JmisM = np.subtract(HMVv,d) invR = np.linalg.inv(R) RJmis = np.dot(invR,Jmis) RJmisM = np.dot(invR,JmisM) HT = np.transpose(H) g1 = np.dot(HT,RJmis) g1M = np.dot(HT,RJmisM) ##MT = ... MT(g1M) = from importance map t_k+1 , map at t_k VT = np.transpose(V) ##VTMT = np.dot(VT,MT) g2 = np.dot(VT,g1) ggJ = v + g2 ##+ VTMT return ggJ #print "exectuable which has been selected:", opal_options.executable # ......... read the input ......... ############################################### ## TRUNCATION AND REGULARIZATION PARAMETERS ### ############################################### # inputs n = 852 lam = 1 #REGULARIZATION PARAMETER m = 45 #TRUNCATION PARAMETER FROM buildV.py xB = np.ones(n) y = np.ones(n) k = 8 # time at which observation is known ############################################### ######## INTIAL RUN OF FLUIDITY ############# ############################################### # put checkpointing on for file k print "name of fwd_input_file", opal_options.data_assimilation.fwd_input_file libspud.load_options('2d_canyon.flml')#(opal_options.data_assimilation.fwd_input_file) # don't need these currently if libspud.have_option('io/checkpointing/checkpoint_at_start'): libspud.delete_option('io/checkpointing/checkpoint_at_start') if libspud.have_option('io/checkpointing/checkpoint_at_end'): libspud.delete_option('io/checkpointing/checkpoint_at_end') if libspud.have_option('io/checkpointing/checkpoint_period_in_dumps'): libspud.set_option('io/checkpointing/checkpoint_period_in_dumps',k) else: print "checkpoint_period_in_dumps option missing from xml file" sys.exit(0) libspud.write_options(opal_options.data_assimilation.fwd_input_file) libspud.clear_options() string = opal_options.executable + " " + opal_options.data_assimilation.fwd_input_file # run code which will checkpoint every "k" dumps at the moment.... print string os.system(string) ############################################### ######## COVARIANCE MATRICES ############# ############################################### V = np.loadtxt('matrixVprec'+str(m)+'.txt', usecols=range(m)) R = lam * 0.5 * np.identity(n) H = np.identity(n) ############################################### ####### FROM PHYSICAL TO CONTROL SPACE ######## ############################################### x0 = np.ones(n) Vin = np.linalg.pinv(V) v0 = np.dot(Vin,x0) ############################################### ####### COMPUTE THE MISFIT ######## ############################################### VT = np.transpose(V) HxB = np.dot(H,xB) # consider multiple observations later - just one for now d = np.subtract(y,HxB) ############################################### ####### COMPUTE THE MINIMUM OF J ######## ############################################### t = time.time() iter_count = 0 Model_updated = False res = minimize(J, v0, method='L-BFGS-B', jac=gradJ, options={'disp': True}) ############################################### ####### FROM CONTROL TO PHYSICAL SPACE ######## ############################################### vDA = np.array([]) vDA = res.x deltaxDA = np.dot(V,vDA) xDA = xB + deltaxDA elapsed = time.time() - t print " iter_count", iter_count #return ############################################### ####### PRECONDITIONED COST FUNCTION J ######## ############################################### return
def fill(self, optionpath, system, index): """Fill a function class with data describing that function using libspud, the given optionpath and the system its based on.""" self.name = libspud.get_option(optionpath+"/name") self.symbol = libspud.get_option(optionpath+"/ufl_symbol").split("\n")[0] self.system = system self.index = index self.type = libspud.get_option(optionpath+"/type/name") self.rank = libspud.get_option(optionpath+"/type/rank/name") self.family = None self.degree = None self.functional = None if self.type != "Constant": self.family = libspud.get_option(optionpath+"/type/rank/element/family") self.degree = libspud.get_option(optionpath+"/type/rank/element/degree") self.size = None self.shape = None self.symmetry = None if self.rank == "Vector": if libspud.have_option(optionpath+"/type/rank/element/size"): self.size = libspud.get_option(optionpath+"/type/rank/element/size") elif self.rank == "Tensor": if libspud.have_option(optionpath+"/type/rank/element/shape"): self.shape = libspud.get_option(optionpath+"/type/rank/element/shape") if libspud.have_option(optionpath+"/type/rank/element/symmetric"): self.symmetry = True self.enrichment_family = None self.enrichment_degree = None if libspud.have_option(optionpath+"/type/rank/element/enrichment"): self.enrichment_family = libspud.get_option(optionpath+"/type/rank/element/enrichment/element/family") self.enrichment_degree = libspud.get_option(optionpath+"/type/rank/element/enrichment/element/degree") # this should be restricted by the schema to Constant coefficients: if libspud.have_option(optionpath+"/type/rank/value/functional"): functional_optionpath = optionpath+"/type/rank/value/functional" functional = buckettools.spud.SpudFunctionalBucket() functional.fill(functional_optionpath, self.system, self) self.functional = functional self.cpp = [] for k in range(libspud.option_count(optionpath+"/type/rank/initial_condition")): cpp_optionpath = optionpath+"/type/rank/initial_condition["+`k`+"]" if libspud.have_option(cpp_optionpath+"/cpp"): cpp_name = libspud.get_option(cpp_optionpath+"/name") cppexpression = buckettools.spud.SpudCppExpressionBucket() # get all the information about this expression from the options dictionary cppexpression.fill(cpp_optionpath, cpp_name, self) # let the field know about this cpp expression self.cpp.append(cppexpression) # done with this expression del cppexpression for j in range(libspud.option_count(optionpath+"/type/rank/boundary_condition")): bc_optionpath = optionpath+"/type/rank/boundary_condition["+`j`+"]" bc_name = libspud.get_option(bc_optionpath+"/name") for k in range(libspud.option_count(bc_optionpath+"/sub_components")): bc_comp_optionpath = bc_optionpath+"/sub_components["+`k`+"]" bc_comp_name = libspud.get_option(bc_comp_optionpath+"/name") cpp_optionpath = bc_comp_optionpath+"/type" if libspud.have_option(cpp_optionpath+"/cpp"): cpp_name = bc_name + bc_comp_name cppexpression = buckettools.spud.SpudCppExpressionBucket() # get all the information about this expression from the options dictionary cppexpression.fill(cpp_optionpath, cpp_name, self) # let the field know about this cpp expression self.cpp.append(cppexpression) # done with this expression del cppexpression for k in range(libspud.option_count(optionpath+"/type/rank/value")): cpp_optionpath = optionpath+"/type/rank/value["+`k`+"]" if libspud.have_option(cpp_optionpath+"/cpp"): cpp_name = libspud.get_option(cpp_optionpath+"/name") cppexpression = buckettools.spud.SpudCppExpressionBucket() # get all the information about this expression from the options dictionary cppexpression.fill(cpp_optionpath, cpp_name, self) # let the field know about this cpp expression self.cpp.append(cppexpression) # done with this expression del cppexpression
def get_option(pclass,key,default=None): result = default if libspud.have_option('/'.join((options_base,pclass,key))): result = libspud.get_option('/'.join((options_base,pclass,key))) return result
def main(): parser = argparse.ArgumentParser( prog="plot 2D", description="""Plot a 2D (time vs depth) of a variable""" ) parser.add_argument( '-v', '--verbose', action='store_true', help="Verbose output: mainly progress reports.", default=False ) parser.add_argument( '-s', '--station', choices=['papa', 'india', 'bermuda'], help="Choose a station: india, papa or bermuda", required=True ) parser.add_argument( '--var', choices=['dz', 'chlor', 'det', 'nit', 'zoo', 'phyto', 'pp', 'temp', 'sal', 'rho', 'tke','vertdiff'], help="Choose a variable to plot", required=True ) parser.add_argument( '-m', '--no_mld', help="Do not plot the MLD", required=False, action="store_true", default=False ) parser.add_argument( '--tke', help="Plot MLD based on TKE, not density", action='store_true', default=False ) parser.add_argument( '-z', type=float, help="Maximum depth to plot", default=500, required=False, ) parser.add_argument( '-n', '--nyears', type=int, default=None, help="Number of years to plot. Default is longest time from Fluidity data", required=False, ) parser.add_argument( '--minvalue', default=None, type=float, help="Set a minimum value to use in the plot", required=False, ) parser.add_argument( '--maxvalue', default=None, type=float, help="Set a maximum value to use in the plot", required=False, ) parser.add_argument( '--logscale', help="Use a log colour scale", action='store_true', default=False ) parser.add_argument( 'input', metavar='input', help="Fluidity results directory", ) parser.add_argument( 'output_file', metavar='output_file', help='The output filename' ) args = parser.parse_args() verbose = args.verbose adaptive = False output_file = args.output_file max_depth = args.z plot_tke = args.tke var = args.var minvalue = args.minvalue maxvalue = args.maxvalue logscale = args.logscale if (args.nyears == None): nDays = None else: nDays = args.nyears*365 # actually irrelavent as we do it by day of year... start = datetime.strptime("1970-01-01 00:00:00", "%Y-%m-%d %H:%M:%S") variable = None long_name = None # work out which variable to pull out # 'dz', 'chlor', 'det', 'nit', 'zoo', 'phyto', 'pp', 'temp', 'sal', 'rho', 'tke' if (var == 'dz'): variable = None # don't need one - special case long_name = r'$\delta z$' elif (var == 'chlor'): variable = 'Chlorophyll' long_name = 'Chlorophyll-a ($mmol/m^3$)' elif (var == 'det'): variable = 'Detritus' long_name = 'Detritus ($mmol/m^3$)' elif (var == 'nit'): variable = 'Nutrient' long_name = 'Nitrate ($mmol/m^3$)' elif (var == 'zoo'): variable = 'Zooplankton' long_name = 'Zooplankton ($mmol/m^3$)' elif (var == 'phyto'): variable = 'Phytoplankton' long_name = 'Phytoplankton ($mmol/m^3$)' elif (var == 'pp'): variable = 'DailyAveragedPrimaryProduction' long_name = 'Primary Production ($mmol/m^3$)' elif (var == 'temp'): variable = 'Temperature' long_name = 'Temperature ($^/circ C$)' elif (var == 'sal'): variable = 'Salinity' long_name = 'Salinity ($PSU$)' elif (var == 'rho'): variable = 'Density' long_name = 'Density ($kg/m^3$)' elif (var == 'tke'): variable = 'GLSTurbulentKineticEnergy' long_name = 'Turbulent Kinetic Energy ($m^2s^{-2}$)' elif (var == 'vertdiff'): variable = 'GLSVerticalDiffusivity' long_name = 'Vertical Diffusivity ($m^2s^{-1}$)' else: print "Unknown variable" sys.exit(-1) if (verbose): print "Plot 2D plot of : " files = get_vtus(args.input) if (not verbose): # print progress bar total_vtus = len(files) percentPerVtu = 100.0/float(total_vtus) if (args.station == 'bermuda'): pp_averaged = True else: pp_averaged = False # Are we adaptive - if so, set up some variables # We need maxdepth, min edge length, max edge length, etc # I think the easiest is to parse the flml...glob flml files # that don't have checkpoint in their name... flmls = (glob.glob(os.path.join(args.input, "*.flml"))) flmls.sort() # grab bits of the flml we want if flmls == None or len(flmls) == 0: print "No flml files available: can't check for adaptivity, this might fail..." elif len(flmls) > 1: print "Found multiple FLMLs, using the first one" else: flml = flmls[0] # grab min_edge_length, max_edge_length, bottom depth and starting resolution libspud.load_options(flml) if (libspud.have_option('mesh_adaptivity/')): adaptive = True minEdgeLength = libspud.get_option('/mesh_adaptivity/hr_adaptivity/tensor_field::MinimumEdgeLengths/anisotropic_symmetric/constant')[-1][-1] maxEdgeLength = libspud.get_option('/mesh_adaptivity/hr_adaptivity/tensor_field::MaximumEdgeLengths/anisotropic_symmetric/constant')[-1][-1] maxDepth = libspud.get_option('/geometry/mesh::CoordinateMesh/from_mesh/extrude/regions::WholeMesh/bottom_depth/constant') initial_spacing = min(minEdgeLength,libspud.get_option('/geometry/mesh::CoordinateMesh/from_mesh/extrude/regions::WholeMesh/sizing_function/constant')) nPoints = int(maxDepth/max(initial_spacing,minEdgeLength))+1 # maximum number of points will be at start with uniform resolution if (verbose): print minEdgeLength, maxEdgeLength, maxDepth, nPoints, initial_spacing else: # If not found, it's not adaptive... adaptive = False if (verbose): print "Adaptive run: ", adaptive current_file = 1 # set up our master variables mld = [] data = [] dates = [] depths = [] for vtu in files: if (not verbose): progress(50,current_file*percentPerVtu) # obtain surface values from each dataset try: #if (verbose): # print vtu os.stat(vtu) except: print "No such file: %s" % file sys.exit(1) # open vtu and derive the field indices of the edge at (x=0,y=0) ordered by depth u=vtktools.vtu(vtu) pos = u.GetLocations() ind = get_1d_indices(pos) # deal with depths depth = [-pos[i,2] for i in ind] if (adaptive): depth.extend([maxDepth+1 for i in range(len(ind),nPoints)]) depths.append(depth) # handle time and convert to calendar time time = u.GetScalarField('Time') tt = [time[i] for i in ind] cur_dt = start + timedelta(seconds=time[0]) days = (cur_dt - start).days tt = [days for i in ind] if (adaptive): tt.extend([days for i in range(len(ind),nPoints)]) dates.append( tt ) if plot_tke: d = u.GetScalarField('GLSTurbulentKineticEnergy') den = [d[i] for i in ind] if (adaptive): den.extend([1e-10 for i in range(len(ind),nPoints)]) mld.append(calc_mld_tke(den, depth)) else: # grab density profile and calculate MLD_den d = u.GetScalarField('Density') den = [d[i] * 1000 for i in ind] if (adaptive): den.extend([d[-1]*1000. for i in range(len(ind),nPoints)]) mld.append(calc_mld_den(den, depth, den0=0.125) ) if (var == 'dz'): z = [] for i in range(1,len(depth)): if (depth[i] - depth[i-1] < minEdgeLength): # we're in the region where we've made up the edges... z.append(minEdgeLength) else: z.append(depth[i] - depth[i-1]) z.append(100) # to make sure shape(dz) == shape(depths) data.append(vtktools.arr(z)) else: # primprod is depth integrated or averaged, so we need the whole field t = u.GetScalarField(variable) if (var == 'pp'): temp = [6.7*12*8.64e4*t[i] for i in ind] elif (var == 'density'): temp = [1024.0*t[i] for i in ind] else: temp = [t[i] for i in ind] if (adaptive): temp.extend([t[-1] for i in range(len(ind),nPoints)]) data.append(temp) current_file = current_file + 1 if (not nDays): nDays = dates[-1][0] filename = output_file data = numpy.array(data) if (var == 'dz'): # Add or subtract a bit more than edgelength as DZ might be a bit more or less than this min_data = minEdgeLength - (0.1*minEdgeLength) max_data = maxEdgeLength + (0.1*maxEdgeLength) else: if (minvalue == None): min_data = data.min() else: min_data = minvalue if (maxvalue == None): max_data = data.max() else: max_data = maxvalue plot_2d_data(data, depths, dates, filename, long_name, finish_day=nDays,mld_data=mld,max_depth=max_depth,minimum=min_data,maximum=max_data,logscale=logscale)
import libspud print libspud.__file__ libspud.load_options('test.flml') libspud.print_options() print libspud.number_of_children('/geometry') print libspud.get_child_name('geometry', 0) print libspud.option_count('/problem_type') print libspud.have_option('/problem_type') print libspud.get_option_type('/geometry/dimension') print libspud.get_option_type('/problem_type') print libspud.get_option_rank('/geometry/dimension') print libspud.get_option_rank( '/physical_parameters/gravity/vector_field::GravityDirection/prescribed/value/constant' ) print libspud.get_option_shape('/geometry/dimension') print libspud.get_option_shape('/problem_type') print libspud.get_option('/problem_type') print libspud.get_option('/geometry/dimension') libspud.set_option('/geometry/dimension', 3) print libspud.get_option('/geometry/dimension') list_path = '/material_phase::Material1/scalar_field::MaterialVolumeFraction/prognostic/boundary_conditions::LetNoOneLeave/surface_ids' print libspud.get_option_shape(list_path)
def fill(self, optionpath, bucket): """Fill a system class with data describing that system using libspud and the given optionpath.""" self.name = libspud.get_option(optionpath+"/name") self.optionpath = optionpath self.symbol = libspud.get_option(optionpath+"/ufl_symbol").split(os.linesep)[0] self.bucket = bucket self.mesh_name = libspud.get_option(optionpath+"/mesh/name") mesh_optionpath = "/geometry/mesh::"+self.mesh_name self.cell = libspud.get_option(mesh_optionpath+"/source/cell") self.fields = [] for j in range(libspud.option_count(optionpath+"/field")): field_optionpath = optionpath+"/field["+`j`+"]" field = buckettools.spud.SpudFunctionBucket() # get all the information about this field from the options dictionary field.fill(field_optionpath, self, j) # let the system know about this field self.fields.append(field) # remove the local copy of this field del field self.coeffs = [] for j in range(libspud.option_count(optionpath+"/coefficient")): coeff_optionpath = optionpath+"/coefficient["+`j`+"]" coeff = buckettools.spud.SpudFunctionBucket() # get all the information about this coefficient from the options dictionary coeff.fill(coeff_optionpath, self, j) # let the system know about this coefficient self.coeffs.append(coeff) # remove the local copy of this coefficient del coeff self.special_coeffs = [] if libspud.have_option("/timestepping"): coeff_optionpath = "/timestepping/timestep/coefficient::Timestep" coeff = buckettools.spud.SpudFunctionBucket() # get all the information about this coefficient from the options dictionary coeff.fill(coeff_optionpath, self, 0) # let the system know about this coefficient self.special_coeffs.append(coeff) # remove the local copy of this coefficient del coeff self.solvers = [] for j in range(libspud.option_count(optionpath+"/nonlinear_solver")): solver_optionpath = optionpath+"/nonlinear_solver["+`j`+"]" solver = buckettools.spud.SpudSolverBucket() # get all the information about this nonlinear solver from the options dictionary solver.fill(solver_optionpath, self) # let the system know about this solver self.solvers.append(solver) # done with this nonlinear solver del solver self.functionals = [] for j in range(libspud.option_count(optionpath+"/functional")): functional_optionpath = optionpath+"/functional["+`j`+"]" functional = buckettools.spud.SpudFunctionalBucket() # get all the information about this functional from the options dictionary functional.fill(functional_optionpath, self) # let the system know about this functional self.functionals.append(functional) # done with this functional del functional