def __init__(self, options_file=None): if options_file: libspud.load_options(options_file) self.simulation_name = libspud.get_option('/simulation_name') self.dimension = libspud.get_option('/geometry/dimension')
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 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") # 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
def compute_diagnostics(self): diagnostic_field_count = libspud.option_count("/system/diagnostic_fields/diagnostic") if(diagnostic_field_count == 0): return LOG.info("Computing diagnostic fields...") d = Diagnostics(self.mesh) for i in range(0, diagnostic_field_count): name = libspud.get_option("/system/diagnostic_fields/diagnostic[%d]/name" % i) try: if(name == "grid_reynolds_number"): viscosity = Function(self.W.sub(1)).interpolate(Expression(libspud.get_option("/system/equations/momentum_equation/stress_term/scalar_field::Viscosity/value/constant"))) field = d.grid_reynolds_number(self.u, viscosity) elif(name == "courant_number"): field = d.courant_number(self.u, self.options["dt"]) else: raise ValueError("Unknown diagnostic field: %s" % name) except ValueError as e: LOG.exception(name) sys.exit() LOG.info("Diagnostic results for: %s" % name) LOG.info("Maximum value: %f" % max(field.vector())) LOG.info("Maximum value: %f" % min(field.vector())) return
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 fill_subforms(self, optionpath, prefix=""): for i in range(libspud.option_count(optionpath+"/form")): form_optionpath = optionpath+"/form["+`i`+"]" self.form_names.append(prefix+libspud.get_option(form_optionpath+"/name")) self.forms.append(libspud.get_option(form_optionpath)+os.linesep) self.form_symbols.append(libspud.get_option(form_optionpath+"/ufl_symbol").split(os.linesep)[0]) self.form_ranks.append(int(libspud.get_option(form_optionpath+"/rank")))
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 compute_diagnostics(self): diagnostic_field_count = libspud.option_count( "/system/diagnostic_fields/diagnostic") if (diagnostic_field_count == 0): return LOG.info("Computing diagnostic fields...") d = Diagnostics(self.mesh) for i in range(0, diagnostic_field_count): name = libspud.get_option( "/system/diagnostic_fields/diagnostic[%d]/name" % i) try: if (name == "grid_reynolds_number"): viscosity = Function(self.W.sub(1)).interpolate( Expression( libspud.get_option( "/system/equations/momentum_equation/stress_term/scalar_field::Viscosity/value/constant" ))) field = d.grid_reynolds_number(self.u, viscosity) elif (name == "courant_number"): field = d.courant_number(self.u, self.options["dt"]) else: raise ValueError("Unknown diagnostic field: %s" % name) except ValueError as e: LOG.exception(name) sys.exit() LOG.info("Diagnostic results for: %s" % name) LOG.info("Maximum value: %f" % max(field.vector())) LOG.info("Maximum value: %f" % min(field.vector())) return
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, 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 __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_solver_parameters(self): """ Get the parameters for the SNES and linear solvers. """ LOG.debug("Defining solver_parameters dictionary...") # NOTE: use 'snes_type': 'newtonls' for production runs. solver_parameters = {'ksp_monitor': True, 'ksp_view': False, 'pc_view': False, 'snes_type': 'ksponly', 'snes_rtol': 1e-7, 'ksp_max_it': 10000} # 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' return solver_parameters
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_filename(self): """Return the mesh file name""" if Parallel.is_parallel(): return libspud.get_option( '/geometry/mesh::CoordinateMesh/from_file/file_name' ) + '_%d.msh' % Parallel.get_rank() # otherwise return libspud.get_option( '/geometry/mesh::CoordinateMesh/from_file/file_name') + '.msh'
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"): c = libspud.get_child_name(option_path + "/type::%s/", 1) self.value.append(libspud.get_option(option_path + "/type::%s/align_bc_with_cartesian/%s_component/%s" % (self.type, c))) else: self.value = 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 fill_subforms(self, optionpath, prefix=""): for i in range(libspud.option_count(optionpath + "/form")): form_optionpath = optionpath + "/form[" + ` i ` + "]" self.form_names.append(prefix + libspud.get_option(form_optionpath + "/name")) self.forms.append(libspud.get_option(form_optionpath) + os.linesep) self.form_symbols.append( libspud.get_option(form_optionpath + "/ufl_symbol").split( os.linesep)[0]) self.form_ranks.append( int(libspud.get_option(form_optionpath + "/rank")))
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 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 __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"): c = libspud.get_child_name(option_path + "/type::%s/", 1) self.value.append( libspud.get_option( option_path + "/type::%s/align_bc_with_cartesian/%s_component/%s" % (self.type, c))) else: self.value = 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 create_best_folders(halloffame): #Create a folder with the best result try: foldername = get_folder_name(halloffame[0]) except: foldername = "" #New name for the folder newfoldername = "Best_result" os.system("cp -r " + foldername + " " + newfoldername) vtufile = libspud.get_option('/simulation_name') + "_1.vtu" #Now we copy the initial vtu of all the results in the hall of fame, to be able to easily explore # the different well locations as well as the production .csv files newfoldername = "Best_well_configurations" os.system("mkdir " + newfoldername) for k in range(len(halloffame)): foldername = get_folder_name(halloffame[k]) #Copy vtu file in order os.system("cp " + foldername + "/" + vtufile + " " + newfoldername + "/" + "best_result_ranked_" + str(k + 1) + ".vtu") #Copy production .csv file os.system("cp " + foldername + "/" + prod_file + " " + newfoldername + "/" + "best_result_ranked_" + str(k + 1) + ".csv") 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("\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_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_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 Parameters(file_name): try: libspud.load_options(file_name) except: print "This file doesn't exist or is the wrong file type. It should be a .osml file. Use -h for help" sys.exit() try: start = float(libspud.get_option('/diffusion_model/timestepping/start_time',)) end = float(libspud.get_option('/diffusion_model/timestepping/end_time')) time_step = float(libspud.get_option('/diffusion_model/timestepping/timestep')) mesh_int = int(libspud.get_option('/diffusion_model/mesh/initial_mesh_size')) alpha = float(libspud.get_option('/diffusion_model/model_parameters/diffusion_coefficient')) initial_conditions = str(libspud.get_option('/diffusion_model/model_parameters/topography_conditions')) sediment_conditions =str(libspud.get_option('/diffusion_model/model_parameters/sediment_conditions')) except: print 'The information provided was incomplete, please recreate the file' sys.exit() if ((start-end) >= 0): print 'The start time is after the end time' sys.exit() elif (time_step == 0): print 'The time step cannot be 0' sys.exit() elif (mesh_int == 0): print 'The mesh has to have a size greater than 0' sys.exit() elif ((end - start) < time_step): print 'The time step is too large for the total time' sys.exit() return start, end, time_step, mesh_int, alpha, initial_conditions, sediment_conditions
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 __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 geterrors(self,checkpoint_file): """ reads checkpoint file and accompanying .xml solution file and extracts the time, and calculates shape and phase errors for the solitary waves """ # this seems to be a dangerous thing but I'm going to clear # the option then load the new ones from the checkpoint file libspud.clear_options() libspud.load_options(checkpoint_file) time = libspud.get_option("/timestepping/current_time") dt = libspud.get_option("/timestepping/timestep/coefficient/type/rank/value/constant") print "t=",time," dt=", dt #load xml file xml_file = checkpoint_file.replace("checkpoint",self.system_name) xml_file = xml_file.replace("tfml","xml") # load function and extract porosity u = df.Function(self.functionspace,xml_file) fields = u.split(deepcopy = True) f = fields[self.f_index] #initialize Error Object err = WaveError(f,self.swave,self.x0,self.h) #minimize error using fsolve #out = err.min_grad(delta_0) delta_0=np.zeros(self.dim) out = err.min_grad_z(delta_0[-1]) delta = out[0] err_min = out[1] elapsed_time = out[2] L2_f= err.L2_f rel_error = err_min/L2_f c_rel_error = np.sign(delta)*np.sqrt(np.dot(delta,delta))/(self.swave.c*time) #print "delta=",delta, " err =",err_min, " elapsed_time=",elapsed_time #print "L2_f=",L2_f, "rel_err =",rel_error, " c_rel_error=",c_rel_error #print "L2_error=",err_min," delta=",delta," rel_error=",rel_error," c_rel_error=",c_rel_error return [time,dt,err_min,delta,rel_error,c_rel_error,elapsed_time]
def geterrors(self, checkpoint_file): """ reads checkpoint file and accompanying .xml solution file and extracts the time, and calculates shape and phase errors for the solitary waves """ # this seems to be a dangerous thing but I'm going to clear # the option then load the new ones from the checkpoint file libspud.clear_options() libspud.load_options(checkpoint_file) time = libspud.get_option("/timestepping/current_time") dt = libspud.get_option( "/timestepping/timestep/coefficient/type/rank/value/constant") print "t=", time, " dt=", dt #load xml file xml_file = checkpoint_file.replace("checkpoint", self.system_name) xml_file = xml_file.replace("tfml", "xml") # load function and extract porosity u = df.Function(self.functionspace, xml_file) fields = u.split(deepcopy=True) f = fields[self.f_index] #initialize Error Object err = WaveError(f, self.swave, self.x0, self.h) #minimize error using fsolve #out = err.min_grad(delta_0) delta_0 = np.zeros(self.dim) out = err.min_grad_z(delta_0[-1]) delta = out[0] err_min = out[1] elapsed_time = out[2] L2_f = err.L2_f rel_error = err_min / L2_f c_rel_error = np.sign(delta) * np.sqrt(np.dot( delta, delta)) / (self.swave.c * time) #print "delta=",delta, " err =",err_min, " elapsed_time=",elapsed_time #print "L2_f=",L2_f, "rel_err =",rel_error, " c_rel_error=",c_rel_error #print "L2_error=",err_min," delta=",delta," rel_error=",rel_error," c_rel_error=",c_rel_error return [time, dt, err_min, delta, rel_error, c_rel_error, elapsed_time]
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 prepare_inputs_for_forward_model(k): ''' make directory to run the fowrard model in, copy across the input files and modify the time step in flml so the forward model will run just for one time step''' # make a directory to run the code in and copy across input files cwd = os.getcwd() input_file_name = "fwd_model.flml" # print "files in cwd" # for files in os.listdir(cwd): # print files if not os.path.isdir( str(k) ): print "attempting to mkdir" os.mkdir(str(k)) os.system('cp *.msh ' + str(k)) os.system('cp *_' +str(k)+ '_checkpoint* ' + str(k)) os.chdir(str(k)) # modify the checkpoint file times for files in os.listdir('./'): # get the name of the checkpoint flml if files.endswith(str(k)+"_checkpoint.flml"): # pos = files.rfind('.') checkpoint_file_name = files # print "checkpoint fname", checkpoint_file_name # load options from checkpoint file libspud.load_options(checkpoint_file_name) # change the name of the output libspud.set_option('/simulation_name','2d_canyon') # change the final time so it runs from t_k to t_k+1 only t0 = libspud.get_option('/timestepping/current_time') dt = libspud.get_option('/timestepping/timestep') libspud.set_option('/timestepping/finish_time',t0+dt) # could check with vtu's that these are the correct times # rename input file libspud.write_options(input_file_name) libspud.clear_options() os.chdir(cwd) return input_file_name
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 get_walltime(foldername, cwd): from fluidity_tools import stat_parser as stat walltime = 1e50 ##Get into the folder os.chdir(foldername) output_name = libspud.get_option('/simulation_name') walltime = stat('./' + output_name + '.stat')["ElapsedWallTime"]["value"][-1] ##Return to original path os.chdir(cwd) return walltime
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 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(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 test11(self): #should be an osml file libspud.load_options('test11.osml') start = float( libspud.get_option('/diffusion_model/timestepping/start_time', )) end = float( libspud.get_option('/diffusion_model/timestepping/end_time')) time_step = float( libspud.get_option('/diffusion_model/timestepping/timestep')) mesh_int = int( libspud.get_option('/diffusion_model/mesh/initial_mesh_size')) alpha = float( libspud.get_option( '/diffusion_model/model_parameters/diffusion_coefficient')) initial_conditions = str( libspud.get_option( '/diffusion_model/model_parameters/initial_conditions')) #create a simple testcase model = SedimentModel() mesh = UnitSquareMesh(mesh_int, mesh_int) model.set_mesh(mesh) init_cond = Expression(initial_conditions) # simple slope init_sed = Expression('x[0]') # this gives # total of above gives a slope of 0 to 2 (over the unit square) model.set_initial_conditions(init_cond, init_sed) model.set_end_time(end) model.set_diffusion_coeff(alpha) model.init() model.solve() # answer should be 1 everywhere plot(model.get_total_height(), interactive=True) answer = model.get_total_height_array()
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 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 test14(self): with self.assertRaises(SystemExit): #should be an osml file libspud.load_options('test14.osml') start = float(libspud.get_option('/diffusion_model/timestepping/start_time',)) end = float(libspud.get_option('/diffusion_model/timestepping/end_time')) time_step = float(libspud.get_option('/diffusion_model/timestepping/timestep')) mesh_int = int(libspud.get_option('/diffusion_model/mesh/initial_mesh_size')) alpha = float(libspud.get_option('/diffusion_model/model_parameters/diffusion_coefficient')) initial_conditions = str(libspud.get_option('/diffusion_model/model_parameters/initial_conditions')) if ((start-end) >= 0): print 'The start time is after the end time' sys.exit() elif (time_step == 0): print 'The time step cannot be 0' sys.exit() #create a simple testcase model = SedimentModel() mesh = UnitSquareMesh(mesh_int,mesh_int) model.set_mesh(mesh) init_cond = Expression(initial_conditions) # simple slope init_sed = Expression('x[0]') # this gives # total of above gives a slope of 0 to 2 (over the unit square) model.set_initial_conditions(init_cond,init_sed) model.set_end_time(end) model.set_diffusion_coeff(alpha) model.init() model.solve() # answer should be 1 everywhere plot(model.get_total_height(),interactive=True) answer = model.get_total_height_array()
def test8(self): #should be an osml file libspud.load_options('test8.osml') start = float(libspud.get_option('/diffusion_model/timestepping/start_time',)) end = float(libspud.get_option('/diffusion_model/timestepping/end_time')) time_step = float(libspud.get_option('/diffusion_model/timestepping/timestep')) mesh_int = int(libspud.get_option('/diffusion_model/mesh/initial_mesh_size')) alpha = float(libspud.get_option('/diffusion_model/model_parameters/diffusion_coefficient')) initial_conditions = str(libspud.get_option('/diffusion_model/model_parameters/initial_conditions')) #create a simple testcase model = SedimentModel() mesh = UnitSquareMesh(mesh_int,mesh_int) model.set_mesh(mesh) init_cond = Expression(initial_conditions) # simple slope init_sed = Expression('x[0]') # this gives # total of above gives a slope of 0 to 2 (over the unit square) model.set_initial_conditions(init_cond,init_sed) model.set_end_time(end) model.set_diffusion_coeff(alpha) model.init() model.solve() # answer should be 1 everywhere plot(model.get_total_height(),interactive=True) answer = model.get_total_height_array() for i in answer: self.assert_(-1e-8 < i - 1 < 1e-8)
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 __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_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 modify_experiment(input_file, foldername, instance, cwd): def modify_input_file(INPUT_FILE): # Read in the file with open(INPUT_FILE, 'r') as file: filedata = file.read() # Convert to physical values instance_bak = convert_instance(instance) ##Substitute a given pattern by the instance value for i in range(opal_options.ga_locations_to_study): for j in range(len(opal_options.ga_variables)): normaliser = opal_options.ga_variables[j].normaliser filedata = filedata.replace( opal_options.ga_variables[j].variable_pattern + str(i + 1), str( float(instance_bak[j + len(opal_options.ga_variables) * i]) / float(normaliser))) # Overwrite file with open(INPUT_FILE, 'w') as file: file.write(filedata) ##Get into the folder os.chdir(foldername) #Modify trelis input file if requested if len(input_file) > 1: modify_input_file(input_file) #Run trelis to create new exodusII file given the instance string = opal_options.trelis_path + " -nographics -nojournal -batch " + opal_options.trelis_input_file os.system(string) #Now convert the output .e file into .msh meshfile = libspud.get_option( '/geometry/mesh::CoordinateMesh/from_file/file_name') convertExodusII2MSH(meshfile) #Decompose the mesh is required if opal_options.MPI_runs > 1: os.system("fldecomp -n " + str(opal_options.MPI_runs) + " " + meshfile) # Now convert the outp #Modify the mpml file if requested if opal_options.optimise_input: modify_input_file(opal_options.input_file) ##Return to original path os.chdir(cwd) return
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 test17(self): with self.assertRaises(SystemExit): #should be an osml file libspud.clear_options() try: libspud.load_options('test17.osml') except: print "This file doesn't exist or is the wrong file type. It should be a .osml file" sys.exit() try: start = float(libspud.get_option('/diffusion_model/timestepping/start_time',)) end = float(libspud.get_option('/diffusion_model/timestepping/end_time')) time_step = float(libspud.get_option('/diffusion_model/timestepping/timestep')) mesh_int = int(libspud.get_option('/diffusion_model/mesh/initial_mesh_size')) alpha = float(libspud.get_option('/diffusion_model/model_parameters/diffusion_coefficient')) initial_conditions = str(libspud.get_option('/diffusion_model/model_parameters/initial_conditions')) except: print 'The information provided was incomplete, please recreate the file' sys.exit() print start print end print time_step print mesh_int print alpha print initial_conditions #create a simple testcase model = SedimentModel() mesh = UnitSquareMesh(mesh_int,mesh_int) model.set_mesh(mesh) init_cond = Expression(initial_conditions) # simple slope init_sed = Expression('x[0]') # this gives # total of above gives a slope of 0 to 2 (over the unit square) model.set_initial_conditions(init_cond,init_sed) model.set_end_time(end) model.set_diffusion_coeff(alpha) model.init() model.solve() # answer should be 1 everywhere plot(model.get_total_height(),interactive=True) answer = model.get_total_height_array()
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 __init__(self, path): self.path = path self.name = libspud.get_option(path+'/name')
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 __init__(self, path): """ Initialise a new shallow water simulation, using an options file. :param str path: The path to the simulation's configuration/options file. :returns: None """ LOG.info("Initialising simulation...") # Remove any stored options. libspud.clear_options() # Load the options from the options tree. libspud.load_options(path) # Populate the options dictionary self.populate_options() # Read in the input mesh (or construct one) self.mesh = self.get_mesh(path) # Create a dictionary containing all the function spaces LOG.info("Creating function spaces...") self.function_spaces = {} # The Velocity field's function space name = "VelocityFunctionSpace" path = "/function_spaces/function_space::%s" % name family = libspud.get_option(path+"/family") degree = libspud.get_option(path+"/degree") try: if(family == "Continuous Lagrange"): self.function_spaces[name] = VectorFunctionSpace(self.mesh, "CG", degree) elif(family == "Discontinuous Lagrange"): self.function_spaces[name] = VectorFunctionSpace(self.mesh, "DG", degree) else: raise ValueError("Unknown element family: %s." % family) except ValueError as e: LOG.exception(e) sys.exit() LOG.debug("Created a new %s function space of degree %d for Velocity" % (family, degree)) # The FreeSurfacePerturbation field's function space name = "FreeSurfaceFunctionSpace" path = "/function_spaces/function_space::%s" % name family = libspud.get_option(path+"/family") degree = libspud.get_option(path+"/degree") try: if(family == "Continuous Lagrange"): self.function_spaces[name] = FunctionSpace(self.mesh, "CG", degree) elif(family == "Discontinuous Lagrange"): self.function_spaces[name] = FunctionSpace(self.mesh, "DG", degree) else: raise ValueError("Unknown element family: %s." % family) except ValueError as e: LOG.exception(e) sys.exit() LOG.debug("Created a new %s function space of degree %d for FreeSurfacePerturbation" % (family, degree)) # Define the mixed function space U = self.function_spaces["VelocityFunctionSpace"] H = self.function_spaces["FreeSurfaceFunctionSpace"] self.W = MixedFunctionSpace([U, H]) # Set up the output streams self.create_output_streams() return
def quadrature_degree(self): return int(libspud.get_option('/geometry/quadrature/degree'))
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