def line_mesh(xmin, xblocks): """ create evenly spaced mesh given endpoints and number of elements """ coords = np.array([xmin]) for i, (xlen, xint) in enumerate(xblocks): xl = coords[-1] xr = xl + xlen n = xint + 1 # check for bad inputs if xl >= xr: raise UserInputError("BLOCK {0}: xl > xr".format(i)) if n <= 0: raise UserInputError("XBLOCK {0}: negative interval".format(i)) # find element seperation block_coords = np.linspace(xl, xr, n) #force location of endpoints block_coords[0] = xl block_coords[-1] = xr coords = np.append(coords, block_coords[1:]) continue nel = coords.size - 1 conn = np.array([[i, i + 1] for i in range(nel)]) return coords, conn
def check_coords_and_conn(dim, coords, connect): """Check the coordinates and connectivity arrays """ # coords if not np.any(coords): raise UserInputError("No coords given") coords = np.array(coords) if coords.shape[1] == 2: coords = np.hstack((coords, np.zeros((coords.shape[0], 1)))) nnodes = coords.shape[0] # connectivity if not np.any(connect): raise UserInputError("No nodal connectivity given") conn = [] for lmn, nodes in enumerate(connect): if max(nodes) > nnodes: raise UserInputError( "Node number {0} in connect exceeds number " "of nodes in coords".format(max(nodes))) conn.append(nodes) continue connect = np.array(conn) return coords, connect
def pBoundary(self, element_list): """Parse a boundary element """ boundary = {} if not element_list: raise UserInputError("Boundary: input not found") if len(element_list) > 1: raise UserInputError( "Boundary: expected 1 block, found: {0}".format( len(element_list))) element = element_list[0] prdisps = self.parse_prescribed_displacement_block( element.getElementsByTagName("PrescribedDisplacement")) boundary["PrescribedDisplacement"] = prdisps prforces = self.parse_prescribed_force_block( element.getElementsByTagName("PrescribedForce")) boundary["PrescribedForce"] = prforces tractions = self.parse_traction_block( element.getElementsByTagName("Traction")) boundary["Traction"] = tractions return boundary
def get_node_sets(node_sets_element): """Parse Mesh.Set.Nodeset element trees Three options for specifying nodeset: sub_domain, nodes, point """ node_sets = [] for node_set in node_sets_element: nsid = node_set.attributes.get("id") if nsid is None: raise UserInputError("Set: Nodeset: 'id' not found") nsid = int(nsid.value.strip()) dom = node_set.attributes.get("sub_domain") if dom is not None: dom = dom.value.strip().upper() nodes = node_set.attributes.get("nodes") if nodes is not None: nodes = str2list(nodes.value.strip()) point = node_set.attributes.get("atpoint") if point is not None: point = str2list(point.value.strip(), dtype=float) point += [0.] * (3 - len(point)) point = dict(zip(("X", "Y", "Z"), point)) spec = [x for x in (dom, nodes, point) if x is not None] if not spec: raise UserInputError("Set: Nodeset: expected one of " "{sub_domain, nodes, atpoint}") elif len(spec) > 1: raise UserInputError("Set: Nodeset: specify only one of " "{sub_domain, nodes, atpoint}") node_sets.append([nsid, spec[0]]) return node_sets
def pBlocks(self, element_list): """Parse the Blocks block """ if not element_list: raise UserInputError("Blocks: input not found") if len(element_list) > 1: raise UserInputError("Blocks: expected 1 block, found: {0}".format( len(element_list))) element = element_list[0] blocks = {} for block in element.getElementsByTagName("Block"): blkid = block.attributes.get("id") if blkid is None: raise UserInputError("Blocks.Block: id not found") blkid = int(blkid.value) material = block.attributes.get("material") if material is None: raise UserInputError("Blocks.Block({0}): material not " "found".format(blkid)) material = int(material.value) blocks[blkid] = (material, ) return blocks
def parse_prescribed_displacement_block(elements): prescribed_displacements = [] attributes = ("constant", "function", "dof", "scale", "nodeset") for (i, element) in enumerate(elements): const = element.attributes.get("constant") func = element.attributes.get("function") scale = element.attributes.get("scale") dof = element.attributes.get("dof") nodeset = element.attributes.get("nodeset") # check for required arguments and conflicts if dof is None: raise UserInputError("Boundary.PrescribedDisplacement: dof " "not specified") dof = dof.value.strip() if nodeset is None: raise UserInputError( "Boundary.PrescribedDisplacement: nodeset " "not specified") nodeset = int(nodeset.value) # either const or func must be specified if const is None: # func must be given if func is None: raise UserInputError( "Boundary.PrescribedDisplacement: " "expected either constant or function " "attribute") func = int(func.value) if scale is None: scale = 1. else: scale = float(scale.value) else: const = float(const.value) if func is not None: raise UserInputError("Boundary.PrescribedDisplacement: " "incompatible attributes: 'function, " "constant'") if scale is not None: raise UserInputError("Boundary.PrescribedDisplacement: " "incompatible attributes: 'scale, " "constant'") func = W_CONST_FCN scale = const assert func is not None, "func is None" assert scale is not None, "scale is None" assert nodeset is not None, "nodeset is None" assert dof is not None, "dof is None" prescribed_displacements.append([func, scale, nodeset, dof]) continue return prescribed_displacements
def format_sidesets(coords, conn, elements, ssets): """Format sidesets Parameters ---------- Returns ------- """ sidesets = [] lims = [] for col in coords.T: lims.append([np.amin(col), np.amax(col)]) lims = np.array(lims) for i, members in ssets: try: dom = members.upper() except AttributeError: dom = None if dom is not None: # user specified as ID, DOM if dom not in ("IHI", "ILO", "JHI", "JLO", "KHI", "KLO"): raise UserInputError( "Domain {0} not recognized".format(dom)) axis = ({ "I": 0, "J": 1, "K": 2 }[dom[0]], { "LO": 0, "HI": 1 }[dom[1:]]) nodes, els = Mesh.nodes_elements_at_pos( coords, conn, axis[0], lims[axis]) # Now get the face numbers for the elements in the sideset faces = [elements[el].topomap(dom) for el in els] ef = [[el, faces[n]] for n, el in enumerate(els)] sidesets.append(Mesh.format_sideset(i, ef)) else: # given as ID, [EL, FACE] # Collect all from a given set and hold for next lines down for member in members: if len(member) != 2: raise UserInputError( "Sidesets must be defined as [el, face], got {0}". format(repr(member))) sidesets.append(Mesh.format_sideset(i, members)) continue return sidesets
def gen_coords_conn_from_inline(etype, mins, blocks): """Generate nodal coordinates and element connectivity from inline specification Parameters ---------- mins : ndarray List of minimums blocks : tuple of ndarray blocks[i] -> [[length, interval]_0, [length, interval]_1, ...] Returns ------- dim : int Dimension coords : ndarray Nodal coordinates connect : ndarray Nodal connectivity """ # Initialize local variables lohi = [(None, None)] * 3 if "bar" in etype.lower(): etype = "BAR" elif "quad" in etype.lower(): etype = "QUAD" elif "hex" in etype.lower(): etype = "HEX" else: raise UserInputError( "{0}: unrecognized inline mesh type".format(etype)) dim = {"BAR": 1, "QUAD": 2, "HEX": 3}[etype.upper()] points = [] for i in range(dim): if not blocks[i]: raise UserInputError("No {0}Block specified for inline " "mesh".format(("X", "Y", "Z")[i])) # Generate the 1d bar mesh in this coordinate line_points, line_conn = line_mesh(mins[i], blocks[i]) lohi[i] = (line_points[0], line_points[-1]) points.append(line_points) continue if dim == 1: # Mesh already created coords = np.array(points[0]) connect = np.array(line_conn) else: coords, connect = brick_mesh(*points) return dim, coords, connect
def from_input_file(cls, fpath, verbosity=None): if not os.path.isfile(fpath): raise UserInputError("{0}: no such file".format(fpath)) fdir, fbase = os.path.split(fpath) fnam, fext = os.path.splitext(fpath) runid = fnam return cls.from_input_string(runid, open(fpath, "r").read(), fdir, verbosity=verbosity)
def distributed_loads(self): if self._distloads is None: return [lambda x: 0.] if len(self._distloads) > 1: raise UserInputError("Only one distributed load for now") distloads = [] for n, distload in self._distloads.items(): func_id = distload["FUNCTION"] scale = distload["SCALE"] blocks = distload["BLOCKS"] # get the function func = self.functions(func_id) if func is None: raise UserInputError("Function {0} not defined".format(func_id)) distloads.append(lambda x, scale=scale: scale * func(x)) continue return distloads
def format_traction_bc(sideset, fcn, scale, conn, coords, elements): """Format a traction boundary condition Parameters ---------- sideset : array_like Formatted sideset list fcn : function The function to apply scale : float Scale factor for function Returns ------- trax : array_like Formatted traction BC """ # sideset[i, j] -> jth face of element i in the sideset tractions = [] for (element, face) in sideset: traction = [element, face] if hasattr(fcn, "__call__"): # tjfulle: hard coded for 2D quad ecls = elements[element] en = ecls.facenodes[face] nodes = conn[element, en] xyz = coords[nodes] # x = (x1, x2), dx = x2 - x1 # y = (y1, y2), dy = y2 - y1 # normal = (-dy, dx), (dy, -dx) dx = np.diff(xyz, axis=0)[0] normal = np.array([dx[1], -dx[0], 0.]) normal = normal / np.sqrt(np.dot(normal, normal)) # Assign components of the traction traction.extend([ lambda x, scale=scale, N=N: fcn(x) * scale * N for N in normal ]) elif isinstance(fcn, list): # All three components of traction force given traction.extend([ lambda x, scale=scale[i]: fcn[i](x) * scale for i in range(3) ]) else: raise UserInputError("Unrecognized traction function type") tractions.append(traction) continue return tractions
def pSolutionControl(self, element_list): """Parse the SolutionControl block and set defaults """ if not element_list: raise UserInputError("SolutionControl: input not found") if len(element_list) > 1: raise UserInputError("SolutionControl: expected 1 block, found: " " {0}".format(len(element_list))) control = [] lowstr = lambda x: str(x).lower() gt = lambda x: x > 0 gte = lambda x: x >= 0 # keyword, default, type, test keywords = (("TimeIntegrator", 0, lambda x: { "implicit": 0, "explicit": 1 }.get(x.lower()), lambda x: x in (0, 1)), ("NumberOfSteps", 10, int, gt), ("Tolerance", 1.e-4, float, gt), ("MaximumIterations", 30, int, gt), ("Relax", 1., float, gt), ("StartTime", 0., float, gte), ("TerminationTime", 10., float, gte), ("TimeStepMultiplier", 1., float, gt), ("Verbosity", 1., int, lambda x: True)) for i, (key, default, dtype, test) in enumerate(keywords): tag = element_list[0].getElementsByTagName(key) if not tag: control.append(default) continue tag = tag[-1].firstChild.data.strip() try: value = dtype(tag) except: raise UserInputError( "SolutionControl: {0}: expected {1}, got {2}".format( key, repr(dtype), tag)) if not test(value): raise UserInputError( "SolutionControl: {0}: invalid value {1}".format( key, value)) control.append(value) return np.array(control)
def fill_in_includes(lines): """Look for 'include' commands in lines and insert then contents in place Parameters ---------- lines : str User input Returns ------- lines : str User input, modified in place, with inserts inserted """ regex = r"<include\s(?P<include>.*)/>" _lines = [] for line in lines.split("\n"): if not line.split(): _lines.append(line.strip()) continue include = re.search(regex, line) if include is None: _lines.append(line) continue href = re.search(r"""href=["'](?P<href>.*?)["']""", include.group("include")) if not href: raise UserInputError("expected href='...'") name = href.group("href").strip() fpath = os.path.realpath(os.path.expanduser(name)) try: fill = open(fpath, "r").read() except IOError: raise UserInputError("{0}: include not found".format(repr(name))) _lines.extend(fill_in_includes(fill).split("\n")) continue return "\n".join(_lines)
def get_side_sets(side_sets_element): """Parse Mesh.Set.Sideset element trees """ side_sets = [] for side_set in side_sets_element: ssid = side_set.attributes.get("id") if ssid is None: raise UserInputError("Set: Sideset: 'id' not found") ssid = int(ssid.value.strip()) dom = side_set.attributes.get("sub_domain") if dom is not None: dom = dom.value.strip().upper() members = side_set.attributes.get("members") if members is not None: # given as element:face pairs matches = re.findall(r"[0-9]+\s*?:\s*?[0-9]+", members.value) members = [[int(i) for i in x.split(":")] for x in matches] for member in members: if len(member) != 2: raise UserInputError("Sidesets must be defined as " "EL:FACE") spec = [x for x in (dom, members) if x is not None] if not spec: raise UserInputError( "Mesh.AssignGroups.Sideset({0}): expected " "one of {sub_domain, members}".foramt(ssid)) if len(spec) > 1: raise UserInputError( "Mesh.AssignGroups.Sideset({0}): expected " "only one of {sub_domain, " "members}".foramt(ssid)) side_sets.append([ssid, spec[0]]) return side_sets
def pMaterials(self, element_list): """Parse the materials block """ if not element_list: raise UserInputError("Materials: input not found") if len(element_list) > 1: raise UserInputError( "Materials: expected 1 block, found: {0}".format( len(element_list))) element = element_list[0] materials = {} for material in element.getElementsByTagName("Material"): mtlid = material.attributes.get("id") if mtlid is None: raise UserInputError("Materials.Material: id not found") mtlid = int(mtlid.value) model = material.attributes.get("model") if model is None: raise UserInputError("Materials.Material: model not found") model = model.value.strip() params = {} for node in material.childNodes: if node.nodeType != material.ELEMENT_NODE: continue val = " ".join(node.firstChild.data.split()) try: params[node.nodeName] = float(val) except ValueError: params[node.nodeName] = str(val) materials[mtlid] = (model, params) return materials
def parse_ascii_mesh(ascii_mesh_element): # check for dim, Vertices, and Connectivity definitions vertices = ascii_mesh_element.getElementsByTagName("Vertices") if not vertices: raise UserInputError("Mesh.ascii: no Vertices found") if len(vertices) > 1: lv = len(vertices) raise UserInputError("Mesh.ascii: expected 1 Vertices block, " "got {0}".format(lv)) connect = ascii_mesh_element.getElementsByTagName("Connectivity") if not connect: raise UserInputError("Mesh.ascii: no Connectivity found") if len(connect) > 1: lc = len(connect) raise UserInputError("Mesh.ascii: expected 1 Connectivity block, " "got {0}".format(lc)) dim = connect[0].attributes.get("dim") if dim is None: raise UserInputError("Mesh.ascii.Connectivity: dim attribute not " "found") dim = int(dim.value) if dim not in (2, 3): raise UserInputError("Mesh.ascii.Connectivity: {0}: invalid " "dim".format(dim)) # Vertices data = [] for line in vertices[0].firstChild.data.split("\n"): line = [float(x) for x in line.split()] if not line: continue if len(line) > 3: ll = len(line) raise UserInputError( "Mesh.ascii: expected 3 vertex coordinates, " "got {0}".format(ll)) data.append(line + [0.] * (3 - len(line))) vertices = np.array(data) # Connectivity data = [] for line in connect[0].firstChild.data.split("\n"): line = [int(x) for x in line.split()] if not line: continue data.append(line) connect = np.array(data) return dim, vertices, connect
def parse_traction_bc(tractions, ssets, coords, connect, elements): """Parse the traction bc. """ trax = [] for (func, scale, sideset_id) in tractions: # now get the actual sideset try: sideset = [x[1] for x in ssets if sideset_id == x[0]][0] except IndexError: raise UserInputError( "Sideset {0} not defined".format(sideset_id)) trax.extend( Mesh.format_traction_bc(sideset, func, scale, connect, coords, elements)) continue return trax
def parse_nodal_forces(self, prforces, nsets): nfrcs = [] for prforce in prforces: fcn = prforce[0] scale = prforce[1] nodeset = prforce[2] key = prforce[3].upper() dofs = default_dofs(self.dim, key) # get the nodes in the nodeset try: nodes = [x[1] for x in nsets if nodeset == x[0]][0] except IndexError: raise UserInputError("Nodeset {0} not defined".format(nodeset)) for dof in dofs: nfrcs.extend(Mesh.format_nodal_force(nodes, dof, fcn, scale)) continue return nfrcs
def parse_displacement_bc(self, prdisps, nsets): dbcs = [] for prdisp in prdisps: fcn = prdisp[0] scale = prdisp[1] nodeset = prdisp[2] key = prdisp[3].upper() dofs = default_dofs(self.dim, key) # get the nodes in the nodeset try: nodes = [x[1] for x in nsets if nodeset == x[0]][0] except IndexError: raise UserInputError("Nodeset {0} not defined".format(nodeset)) for dof in dofs: dbcs.extend(Mesh.format_displacement_bc( nodes, dof, fcn, scale)) continue return dbcs
def pMesh(self, element_list): """Parse the Mesh block and set defaults """ if not element_list: raise UserInputError("Mesh: input not found") if len(element_list) > 1: raise UserInputError("Mesh: expected 1 block, found: {0}".format( len(element_list))) mesh = element_list[0] mesh_type = mesh.attributes.get("type") if mesh_type is None: raise UserInputError("Mesh: mesh type not found") mesh_type = mesh_type.value.strip().lower() node_sets = [] side_sets = [] el_blocks = [] for s in mesh.getElementsByTagName("AssignGroups"): node_sets.extend( self.get_node_sets(s.getElementsByTagName("Nodeset"))) side_sets.extend( self.get_side_sets(s.getElementsByTagName("Sideset"))) el_blocks.extend( self.get_el_blocks(s.getElementsByTagName("Block"))) if not el_blocks: raise UserInputError( "Mesh.AssignGroups: no element block assignments " "found") if mesh_type == "inline": eltype, dim, coords, connect = self.parse_inline_mesh(mesh) for el_block in el_blocks: if eltype.lower()[0] != el_block[1][2]: raise UserInputError( "Mesh.inline: {0}: inconsistent element " "type for assigned block {1}".format( el_block[1], el_block[0])) elif mesh_type == "ascii": dim, coords, connect = self.parse_ascii_mesh(mesh) else: raise UserInputError("{0}: invalid mesh type".format(mesh_type)) return dim, coords, connect, el_blocks, side_sets, node_sets
def form_elements(runid, el_blocks, connect, coords, block_options, materials): elements = [None] * len(connect) for key, val in block_options.items(): mtlid = val[0] el_block = [x for x in el_blocks if x[0] == key][0] elem_blk_id, etype, els, elopts = el_block elopts["RUNID"] = runid mtl_name, mtl_params = materials.get(mtlid, (None, None)) if mtl_name is None: raise UserInputError( "Material {0} not defined in input file".format(mtlid)) # instantiate the material model for element material = create_material(mtl_name) # get the element class for elements in this block ecls = element_class_from_name(etype) # determine volumes of each element v_els = None # Check for any perturbed parameters matparams, perturbed = {}, {} seed(12) for key, val in mtl_params.items(): idx = material.parameter_index(key) if idx is None: recognized = ", ".join(material.param_map) raise UserInputError( "{0}: {1}: unrecognized parameter. " "Recognized parameters are: {2}".format( material.name, key, recognized)) weibull = False if not weibull: matparams[key] = val continue # weibull perturbation requested if v_els is None: v_els = np.array( [ecls.volume(coords[connect[eid]]) for eid in els]) v_ave = np.average(v_els) p0 = val.get("MEDIAN") if p0 is None: raise UserInputError( "{0}: no median value given".format(key)) k = float(val.get("VOLUME EXPONENT", 1.)) m = float(val.get("WEIBULL MODULUS", 10.)) msf = float(val.get("MODULUS SCALE FACTOR", 1.)) p = [ p0 * (v_ave / v_els[i])**(k / m) * (np.log(rand()) / np.log(.5))**(1. / (m * msf)) for i, el in enumerate(els) ] perturbed[key] = (idx, np.array(p)) # Fill parameter array for iel, eid in enumerate(els): p = {} for key, (i, val) in perturbed.items(): p[key] = (i, val[iel]) nodes = connect[eid] nodal_coords = coords[nodes] elements[eid] = ecls(eid, (iel, elem_blk_id), nodes, nodal_coords, material, matparams, p, **elopts) del matparams del perturbed return elements
def get_el_blocks(el_blocks_element): """Parse Mesh.Blocks.Block element trees """ el_blocks = [] unassigned, allassigned = 0, 0 for el_block in el_blocks_element: el_block_id = el_block.attributes.get("id") if el_block_id is None: raise UserInputError("Blocks: Block: 'id' not found") el_block_id = int(el_block_id.value.strip()) # element block elements elements = el_block.attributes.get("elements") if elements is None: raise UserInputError("AssignGroups.Block({0}): no elements " "assigned".format(el_block_id)) elements = elements.value.strip().lower() # check special cases first if elements == "all": allassigned += 1 elif elements == "unassigned": unassigned += 1 if elements not in ("all", "unassigned"): elements = str2list(elements, dtype=int) # element type for block eltype = el_block.attributes.get("eltype") if eltype is None: raise UserInputError("AssignGroups.Block({0}): no eltype " "assigned".format(el_block_id)) eltype = eltype.value.strip().lower() # element options for block elopts = el_block.attributes.get("elopts", {}) if elopts: S = re.findall(r".*?=\s*[\w\.]+.*?", elopts.value) for (i, item) in enumerate(S): item = item.split("=") if len(item) != 2: raise UserInputError("elopts must be of form key=val") try: val = int(item[1]) except ValueError: val = str(item[1]) key = str("_".join(item[0].split()).upper()) S[i] = (key, val) elopts = dict(S) el_blocks.append([el_block_id, eltype, elements, elopts]) if unassigned and allassigned: raise UserInputError( "AssignGroups: elements='all' inconsistent with " "elements='unassigned'") if allassigned and len(el_blocks) > 1: raise UserInputError( "AssignGroups: elements='all' inconsistent with " "mutliple assigned blocks") if unassigned and len(el_blocks) == 1: el_blocks[0][2] = "all" return el_blocks
def parse_traction_block(elements): """Parse the Boundary.Traction element Tractions are given as either constant or function. Alternatively each force component can be specified as components="x=xval y=yval z=zval" """ tractions = [] attributes = ("components", "constant", "sideset", "function", "scale") for (i, element) in enumerate(elements): components = element.attributes.get("components") sideset = element.attributes.get("sideset") const = element.attributes.get("constant") function = element.attributes.get("function") scale = element.attributes.get("scale") # check for required arguments and conflicts if sideset is None: raise UserInputError( "Boundary.Traction: sideset not specified") sideset = int(sideset.value) one_rqd = [ x for x in (const, function, components) if x is not None ] if not one_rqd: raise UserInputError( "Boundary.Traction: expected one of " "(constant, function, components) attribute") if len(one_rqd) > 1: raise UserInputError( "Boundary.Traction: expected only one of " "(constant, function, components) attribute") if components is not None: # components specified, find out which scale = np.zeros(3) components = " ".join(components.value.upper().split()) for i, label in enumerate("XYZ"): S = re.search( "{0}\s*=\s*(?P<val>{1})".format(label, NUMREGEX), components) if S is not None: scale[i] = float(S.group("val")) # assign the constant function function = [W_CONST_FCN] * 3 elif const is not None: const = float(const.value) if scale is not None: raise UserInputError( "Boundary.PrescribedForce: incompatible " "attributes: 'scale, constant'") function = W_CONST_FCN scale = const else: function = int(function.value) if scale is None: scale = 1. else: scale = float(scale.value) assert sideset is not None, "sideset is None" tractions.append([function, scale, sideset]) continue return tractions
def parse_inline_mesh(inline_mesh_element): lmn_types = ("Quad", ) lmn = {} for lmn_type in lmn_types: tags = inline_mesh_element.getElementsByTagName(lmn_type) if not tags: continue if len(tags) > 1: raise UserInputError( "Mesh.inline: expected 1 {0}, got {1}".format( lmn_type, len(tags))) lmn.setdefault(lmn_type, []).append(tags[0]) if not lmn: raise UserInputError( "Mesh.inline: expected one of {0} block types".format( ", ".join(lmn_types))) if len(lmn) > 1: raise UserInputError( "Mesh.inline: expected only one of {0} block types".format( ", ".join(lmn_types))) lmn_type = lmn.keys()[0] lmn = lmn[lmn_type][0] # get [xyz]mins mins = [] for item in ("xmin", "ymin", "zmin"): val = lmn.attributes.get("xmin", 0.) if val: val = float(val.value.strip()) mins.append(val) xyzblocks = [None] * 3 attributes = ("order", "length", "interval") blk_types = ("XBlock", "YBlock", "ZBlock") for i, tag in enumerate(blk_types): o = 0 blks = [] for xyzblock in lmn.getElementsByTagName(tag): blk = [] for item in attributes: attr = xyzblock.attributes.get(item) if not attr: raise UserInputError( "Mesh.inline.{0}: expected {1} attribute".format( tag, item)) attr = float(attr.value.strip()) if item == "order": o += 1 if attr != o: raise UserInputError( "Mesh.inline.{0}s must be ordered " "contiguously".format(tag)) continue blk.append(attr) blks.append(blk) xyzblocks[i] = blks mesh = gen_coords_conn_from_inline(lmn_type, mins, xyzblocks) dim, coords, connect = mesh return lmn_type, dim, coords, connect
def pFunctions(self, element_list): """Parse the functions block """ if len(element_list) > 1: raise UserInputError( "Functions: expected 1 block, found: {0}".format( len(element_list))) functions = {W_CONST_FCN: lambda x: 1.} if not element_list: return functions for function in element_list[0].getElementsByTagName("Function"): fid = function.attributes.get("id") if fid is None: raise UserInputError("Functions.Function: id not found") fid = int(fid.value) if fid == W_CONST_FCN: raise UserInputError("Function id {0} is reserved".format(fid)) if fid in functions: raise UserInputError( "{0}: function already defined".format(fid)) ftype = function.attributes.get("type") if ftype is None: raise UserInputError("Functions.Function: type not found") ftype = " ".join(ftype.value.split()).upper() if ftype not in (AE, PWL): raise UserInputError( "{0}: invalid function type".format(ftype)) expr = function.firstChild.data.strip() if ftype == AE: func, err = build_lambda(expr, disp=1) if err: raise UserInputError("{0}: in analytic expression in " "function {1}".format(err, fid)) elif ftype == PWL: # parse the table in expr try: columns = str2list( function.attributes.get("columns").value, dtype=str) except AttributeError: columns = ["x", "y"] except TypeError: columns = ["x", "y"] table = [] ncol = len(columns) for line in expr.split("\n"): line = [float(x) for x in line.split()] if not line: continue if len(line) != ncol: nl = len(line) raise UserInputError( "Expected {0} columns in function " "{1}, got {2}".format(ncol, fid, nl)) table.append(line) func, err = build_interpolating_function(np.array(table), disp=1) if err: raise UserInputError("{0}: in piecwise linear table in " "function {1}".format(err, fid)) functions[fid] = func continue return functions
def __init__(self, elid, elem_blk_ids, nodes, coords, material, mat_params, perturbed, *args, **kwargs): if len(nodes) != self.nnodes: raise UserInputError("{0}: {1} nodes required, got {2}".format( self.name, self.nnodes, len(nodes))) # set up the model, perturbing parameters if necessary self.material = material for key, (i, val) in perturbed.items(): mat_params[key] = val self.material.setup(mat_params) self.material.initialize_state() self._variables = [] self.reducedint = "REDUCED_INTEGRATION" in kwargs self.planestress = "PLANE_STRESS" in kwargs if self.reducedint and not self.canreduce: raise UserInputError( "Element {0} cannot use reduced integration".format(self.name)) if self.planestress and not self.hasplanestress: raise UserInputError( "Element {0} not plane stress compatible".format(self.name)) ro.reducedint = self.reducedint self.elid = elid self.elid_this_blk, self.elem_blk_id = elem_blk_ids self.ievar = 0 self.register_variable("CAUCHY-STRESS", vtype="SYMTENS") self.register_variable("LEFT-STRETCH", vtype="SYMTENS") self.register_variable("ROTATION", vtype="TENS") self.register_variable("SYMM-L", vtype="SYMTENS") self.register_variable("SKEW-L", vtype="SKEWTENS") self.register_variable("GREEN-STRAIN", vtype="SYMTENS") for var in self.material.variables(): self.register_variable(var, vtype="SCALAR") # Element data array. See comments above. self.nxtra = self.material.nxtra self.ndat = XTRA + self.nxtra + len(perturbed) self._p = XTRA + self.nxtra self.data = np.zeros((2, self.ngauss + 1, self.ndat)) # register perturbed parameters as variables self._pidx = [] for i, (key, (idx, val)) in enumerate(perturbed.items()): self._pidx.append(idx) self.register_variable("{0}_STAT".format(key)) self.data[:, :, self._p + i] = val # Element volume self._volume = self.volume(coords) # initialize nonzero data self.data[:, :, LEFTV:LEFTV + NSYMM] = I6 self.data[:, :, ROTATE:ROTATE + NTENS] = I9 self.data[:, :, XTRA:XTRA + self.nxtra] = self.material.initial_state() # Initialize the stiffness self.kel = np.zeros((self.ndof * self.nnodes, self.ndof * self.nnodes)) pass
def __init__(self, user_input): """Parse the xml input file Parameters ---------- file_name : str path to input file """ user_input = fill_in_includes(user_input) dom = xdom.parseString(user_input) # Get the root element (Should always be "MaterialModel") model_input = dom.getElementsByTagName("WasatchModel") if not model_input: raise UserInputError("Expected Root Element 'WasatchModel'") # ------------------------------------------ get and parse blocks --- # input_blocks = {} recognized_blocks = ("SolutionControl", "Mesh", "Boundary", "Materials", "Functions", "Blocks") for block in recognized_blocks: elements = model_input[0].getElementsByTagName(block) try: parse_function = getattr(self, "p{0}".format(block)) except AttributeError: sys.exit("{0}: not finished parsing".format(block)) input_blocks[block] = parse_function(elements) for element in elements: p = element.parentNode p.removeChild(element) # --------------------------------------------------- check input --- # # 0) pop needed data from input_blocks dict and save # 1) check that functions are defined for entities requiring function # 2) replace function ids with actual function self.control = input_blocks.pop("SolutionControl") self.materials = input_blocks.pop("Materials") self.blk_options = input_blocks.pop("Blocks") self.periodic_masters_slaves = None boundary = input_blocks.pop("Boundary") functions = input_blocks.pop("Functions") (self.dim, self.coords, self.connect, self.el_blocks, self.ssets, self.nsets) = input_blocks.pop("Mesh") # element blocks for blk, items in self.blk_options.items(): # make sure block is defined in mesh if blk not in [x[0] for x in self.el_blocks]: raise UserInputError("Blocks.Block: Block {0} not defined in " "mesh".format(blk)) material = items[0] try: self.materials[material] except KeyError: raise UserInputError("Blocks.Block({0}): material {1} " "not defined".format(blk, material)) # --- boundary self.prdisps = [] for prdisp in boundary.get("PrescribedDisplacement", []): (fid, scale, nodeset, dof) = prdisp func = functions.get(fid) if func is None: raise UserInputError( "Boundary.PrescribedDisplacement function " "{0} not defined".format(fid)) if nodeset not in [x[0] for x in self.nsets]: raise UserInputError("Boundary.PrescribedDisplacement nodeset " "{0} not defined".format(nodeset)) self.prdisps.append([func, scale, nodeset, dof]) self.prforces = [] for (fid, scale, nodeset, dof) in boundary.get("PrescribedForce", []): func = functions.get(fid) if func is None: raise UserInputError("Boundary.PrescribedForce function {0} " "not defined".format(fid)) self.prforces.append([func, scale, nodeset, dof]) self.tractions = [] for (fid, scale, sideset) in boundary.get("Traction", []): # test if fid is a function ID or IDs func = None try: func = [functions[x] for x in fid] except TypeError: # must be an integer func = functions.get(fid) if func is None: raise UserInputError("Boundary.Traction function {0} not " "defined".format(fid)) self.tractions.append([func, scale, sideset]) self.distloads = [] for (fid, scale, blx) in boundary.get("DistributedLoad", []): func = functions.get(fid) if func is None: raise UserInputError("Boundary.DistributedLoad function {0} " "not defined".format(fid)) self.distloads.append([func, scale, blx])
def format_el_blocks(coords, conn, el_blocks): """Format element sets to be passed to exodusii Parameters ---------- coords : ndarray Nodal coordinates conn : ndarray Element connectivity el_blocks : array_like User given element sets *** Returns ------- formatted_el_blocks :array_like Sorted list of element sets formatted_el_blocks[i][j] -> jth element of the ith set Notes ----- el_blocks can be given in one of two ways: 1) Explicitly give each element of a set. [[1, [23, 24, 25]]] would assign element 23, 24, 25 to element set 1 2) Define ranges to find elements [[1, ((xi, xl), (yi, yl), (zi, zl))]] would assign to element set 1 all elements in the ranges. """ formatted_el_blocks, explicit, used = [], [], [] unassigned = None for i, (j, eltype, members, elopts) in enumerate(el_blocks): if members == "all": members = range(len(conn)) if members == "unassigned": unassigned = j continue fromrange = len(members) == 3 and all( [len(x) == 2 for x in members]) # find all element sets that are given explicitly if not fromrange: members = np.array(members, dtype=np.int) formatted_el_blocks.append([j, eltype, members, elopts]) used.extend(members) explicit.append(j) continue # now find elements within given ranges hold = {} for (iel, el) in enumerate(conn): ecoords = coords[el] for i, eltype, members, elopts in el_blocks: if i in explicit or i == unassigned: continue # look for all elements in the given range if all([ np.amin(ecoords[:, 0]) >= members[0][0], np.amax(ecoords[:, 0]) <= members[0][1], np.amin(ecoords[:, 1]) >= members[1][0], np.amax(ecoords[:, 1]) <= members[1][1], np.amin(ecoords[:, 2]) >= members[2][0], np.amax(ecoords[:, 2]) <= members[2][1] ]): hold.setdefault(i, []).append(iel) for iset, members in hold.items(): # get eltype for this set el_block = [x for x in el_blocks if x[0] == iset][0] eltype = el_block[1] elopts = el_block[3] formatted_el_blocks.append([iset, eltype, members, elopts]) used.extend(iset) # put all elements not already assigned in set 'unassigned' used = np.unique(used) orphans = [x for x in range(len(conn)) if x not in used] if orphans: if unassigned is None: raise UserInputError("nothing to do for unassigned elements") el_block = [x for x in el_blocks if x[0] == unassigned][0] eltype = el_block[1] elopts = el_block[3] formatted_el_blocks.append([unassigned, eltype, orphans, elopts]) return sorted(formatted_el_blocks, key=lambda x: x[0])
def create_material(matname): model = models.get(matname.upper()) if model is None: raise UserInputError("model {0} not recognized".format(matname)) return model()