def _check_params(self): """Check parameters and set defaults """ if self._params[self.E] < 0.: raise WasatchError("Young's modulus E must be > 0") if not -1 < self._params[self.NU] < .5: raise WasatchError("Poisson's ratio NU out of bounds") return
def reduce_map(i, j, ncoord, ndof=None): """Mapping from higher order tensor space to lower order Parameters ---------- ij : tuple Indeces in the higher-order tensor space (1, 1) ij[0] -> ith index ij[1] -> jth index Returns ------- I : int Index in the lower-order tensor space Comments -------- Maps according to: 2D 3D 00 -> 0 00 -> 0 11 -> 1 11 -> 1 22 -> 2 01 -> 2 01 -> 3 12 -> 4 02 -> 5 """ ij = (i, j) if ndof is None: ndof = ncoord if ndof != ncoord: raise WasatchError("NDOF must equal NCOORD (for now)") # sort the indices ij = sorted(ij) if ij[0] == ij[1]: return ij[0] if ncoord == 2: if any(i > 1 for i in ij): raise WasatchError("Bad index for 2D mapping: {0}".format( repr(ij))) return 2 if ij == [0, 1]: return 3 elif ij == [1, 2]: return 4 elif ij == [0, 2]: return 5 raise WasatchError("Bad index for 3D mapping: {0}".format(repr(ij)))
def register_variable(self, var, vtype="SCALAR"): """Register element variable """ vtype = vtype.upper() var = var.upper() if vtype == "SCALAR": self._variables.append(var) elif vtype == "TENS": self._variables.extend([ "{0}-{1}".format(var, x) for x in ("XX", "XY", "XZ", "YX", "YY", "YZ", "ZX", "ZY", "ZZ") ]) elif vtype == "SYMTENS": self._variables.extend([ "{0}-{1}".format(var, x) for x in ("XX", "YY", "ZZ", "XY", "YZ", "XZ") ]) elif vtype == "SKEWTENS": self._variables.extend( ["{0}-{1}".format(var, x) for x in ("XY", "YZ", "XZ")]) else: raise WasatchError("{0}: unrecognized vtype".format(vtype))
def parse_input_parameters(self, pdict): self.pdict = pdict for name, val in pdict.items(): i = self.param_map.get(name.upper()) if i is None: if cfg.debug: raise WasatchError( "{0}: {1}: unrecognized parameter".format( self.name, name)) continue self._params[i] = val
def element_data(self, ave=False, exo=False, item=None): """Return the current element data Returns ------- data : array_like Element data """ a, b = 0, self.ndat if item is not None: # Get the index of item try: a, b = DATMAP.get(item.upper()) except TypeError: raise WasatchError("{0}: not in element data".format(item)) if b == -1: b = self.ndat if ave or exo: return self.data[0, self.ngauss][a:b] return self.data[0, :, a:b]
def brick_mesh(xpoints, ypoints, zpoints=None, test=False): """Generate a [2,3]D block mesh. Parameters ---------- xpoints : array_like Points defining the x-axis from x0 to xf ypoints : array_like Points defining the y-axis from y0 to yf zpoints : array_like [optional] Points defining the z-axis from z0 to zf Returns ------- coords : array_like, (i, j) Nodal coordinates coords[i, j] -> jth coordinate of ith node conn : array_like, (i, j) nodal connectivity conn[i, j] -> jth node of the ith element """ dim = 2 if zpoints is None else 3 if dim == 3: raise WasatchError("3D inline mesh not done") shape = [ xpoints.size, ypoints.size, ] if dim == 3: shape.append(zpoints.size) shape = np.array(shape, dtype=np.int) nnode = np.prod(shape) nel = np.prod(shape - 1) # Nodal coordinates if dim == 3: coords = [[x, y, z] for z in zpoints for y in ypoints for x in xpoints] else: coords = [(x, y, 0) for y in ypoints for x in xpoints] coords = np.array(coords, dtype=np.float64) # Connectivity if dim == 2: row = 0 conn = np.zeros((nel, 4), dtype=np.int) nelx = xpoints.size - 1 for lmn in range(nel): ii = lmn + row conn[lmn, :] = [ii, ii + 1, ii + nelx + 2, ii + nelx + 1] if (lmn + 1) % (nelx) == 0: row += 1 continue else: grid = np.zeros(shape, dtype=np.int) for ii, ic in enumerate(_cycle(shape)): grid[tuple(ic)] = ii conn = np.zeros((nel, 8), dtype=np.int) for ii, (ix, iy, iz) in enumerate(_cycle(shape - 1)): conn[ii, :] = [ grid[ix, iy, iz], grid[ix + 1, iy, iz], grid[ix + 1, iy + 1, iz], grid[ix, iy + 1, iz], grid[ix, iy, iz + 1], grid[ix + 1, iy, iz + 1], grid[ix + 1, iy + 1, iz + 1], grid[ix, iy + 1, iz + 1] ] return coords, conn
def run_from_cl(argv=None): if argv is None: argv = sys.argv[1:] parser = argparse.ArgumentParser() parser.add_argument("file") parser.add_argument( "--chk-mesh", default=False, action="store_true", help= "Stop to check mesh before running simulation [default: %(default)s]") parser.add_argument("--piecewise", default=False, action="store_true", help="""Print the piecewise solution as a function of x [default: %(default)s""") parser.add_argument("--dbg", default=False, action="store_true", help="Debug mode [default: %(default)s]") parser.add_argument("--sqa", default=False, action="store_true", help="SQA mode [default: %(default)s]") parser.add_argument("-v", default=1, type=int, help="Verbosity [default: %(default)s]") parser.add_argument("--wm", default=False, action="store_true", help="Write mesh to ascii file [default: %(default)s]") parser.add_argument( "-j", default=1, type=int, help="Number of proccesses to run simultaneously [default: %(default)s]" ) parser.add_argument("-E", default=False, action="store_true", help="Write exodus file [default: %(default)s]") parser.add_argument("--clean", default=False, action="store_true", help="Clean simulation output [default: %(default)s]") parser.add_argument( "--cleanall", default=False, action="store_true", help="Clean all simulation output [default: %(default)s]") parser.add_argument( "--profile", default=False, action="store_true", help="Run the simulation in a profiler [default: %(default)s]") parser.add_argument( "-d", nargs="?", default=None, const="_RUNID_", help="Directory to run analysis [default: %(default)s]") parser.add_argument( "--ccompiler", default="gcc", help=("(Optional) C compiler for compiling weave.inline code " "[default: %(default)s]")) args = parser.parse_args(argv) if args.profile: raise WasatchError("Profiling must be run from __main__") # set some simulation wide configurations set_runopt("SQA", args.sqa) set_runopt("DEBUG", args.dbg) set_runopt("VERBOSITY", args.v) cc = has_c_compiler(args.ccompiler) if args.clean or args.cleanall: from src.base.utilities import clean_wasatch clean_wasatch(os.path.splitext(args.file)[0], args.cleanall) return 0 ti = time.time() infile = os.path.realpath(args.file) if not os.path.isfile(infile): raise SystemExit("{0}: no such file".format(infile)) # find where to run the simulation fdir, fname = os.path.split(infile) runid, ext = os.path.splitext(fname) rundir = args.d or os.getcwd() if rundir != os.getcwd(): # wants to run simulation in alternate directory if rundir == "_RUNID_": rundir = os.path.join(fdir, runid) else: rundir = os.path.realpath(rundir) try: os.makedirs(rundir) except OSError: pass dest = os.path.join(rundir, fname) try: os.remove(dest) except: pass shutil.copyfile(infile, dest) os.chdir(rundir) infile = dest input_lines = open(infile, "r").read() ui = UserInputParser(input_lines) implicit = ui.control[0] == 0. # set up the mesh mesh = femesh.Mesh(runid, ui.dim, ui.coords, ui.connect, ui.el_blocks, ui.ssets, ui.nsets, ui.prdisps, ui.prforces, ui.tractions, ui.blk_options, ui.materials) if implicit: import core.lento as lento fe_model = lento.Lento(runid) else: import core.veloz as veloz fe_model = veloz.Veloz(runid) fe_model.attach_mesh(mesh) fe_model.attach_control(ui.control) fe_model.setup() if args.wm: fe_model.mesh.write_ascii(fe_model.runid) if args.chk_mesh: fe_model.logger.write( "See {0} for initial mesh".format(fe_model.runid + ".exo")) resp = raw_input("Continue with simulation? (Y/N) [N]: ") stop = not {"Y": True}.get(resp.upper().strip(), False) if stop: return 0 try: retval = fe_model.solve(nproc=args.j) except KeyboardInterrupt: sys.stderr.write("\nKeyboard interrupt\n") retval = -1 tf = time.time() fe_model.logger.write( "wasatch: total simulation time: {0:.2f}s".format(tf - ti)) fe_model.logger.close() return retval
def solve(self, nproc=1, disp=0): """ 2D and 3D Finite Element Code Currently configured to run either plane strain in 2D or general 3D but could easily be modified for plane stress or axisymmetry. """ # Local Variables # --------------- # du : array_like, (i,) # Nodal displacements. # Let wij be jth displacement component at ith node. Then du # contains [w00, w01, w10, w11, ...] for 2D # and [w00, w01, w02, w10, w11, w12, ...) for 3D # dw : array_like, (i,) # Correction to nodal displacements. # K : array_like, (i, j,) # Global stiffness matrix. Stored as # [K_1111 K_1112 K_1121 K_1122... # K_1211 K_1212 K_1221 K_1222... # K_2111 K_2112 K_2121 K_2122...] # for 2D problems and similarly for 3D problems # F : array_like, (i, ) # Force vector. # Currently only includes contribution from tractions acting on # element faces (body forces are neglected) # R : array_like, (i, ) # Volume contribution to residual # b : array_like (i, ) # RHS of equation system runid = self.runid control = self.control_params() X = self.mesh.nodes() connect = self.mesh.connect() elements = self.mesh.elements() fixnodes = self.mesh.displacement_bcs() nforces = self.mesh.nodal_forces() tractions = self.mesh.traction_bcs() t0 = time.time() dim = elements[0].ndof nelems = elements.shape[0] nnode = X.shape[0] ndof = elements[0].ndof ncoord = elements[0].ncoord u = np.zeros((nnode * ndof)) du = np.zeros((nnode * ndof)) nodal_stresses = np.zeros((nnode, 6)) # tjf: nodal_state will have to be adjusted for multi-material where # each node may be connected to elements of different material. # nodal_state = np.zeros((nnode, max(el.material.nxtra for el in elements))) nproc = 1. # Simulation setup (tint, nsteps, tol, maxit, relax, tstart, tterm, dtmult, verbosity) = control nsteps, maxit = int(nsteps), int(maxit) t = tstart dt = (tterm - tstart) / float(nsteps) * dtmult global_data.set_var("TIME", t) global_data.set_var("TIME_STEP", dt) nodal_data.set_var("DISPL", u) findstiff = True logger.write_intro("Implicit", runid, nsteps, tol, maxit, relax, tstart, tterm, ndof, nelems, nnode, elements) logger.write(HEAD) for step in range(nsteps): loadfactor = float(step + 1) / float(nsteps) err1 = 1. t += dt # Newton-Raphson loop mult = 10 if step == 0 and ro.reducedint else 1 for nit in range(mult * maxit): # --- Update the state of each element to end of Newton step update_element_states(t, dt, X, elements, connect, u, du) # --- Update nodal stresses for (inode, els) in enumerate(self.mesh._node_el_map): sig = np.zeros(6) # nx = elements[els[0]].material.nxtra # xtra = np.zeros(nx) acc_volume = 0. for iel in els: if iel == -1: break el = elements[iel] vol = el._volume sig += el.element_data(ave=True, item="STRESS") * vol # xtra += el.element_data(ave=True, item="XTRA") * vol acc_volume += vol nodal_stresses[inode][:] = sig / acc_volume # nodal_state[inode][0:nx] = xtra / acc_volume continue # --- Get global quantities if findstiff: gK = global_stiffness(t, dt, X, elements, connect, du, nproc) findstiff = False K = np.array(gK) F = global_traction(t, dt, X, elements, connect, tractions, nforces, du) R = global_residual(t, dt, X, elements, connect, du) b = loadfactor * F - R apply_dirichlet_bcs(ndof, nnode, t, fixnodes, u, du, loadfactor, K, b) # --- Solve for the correction c, dw, info = linsolve(K, b) if info > 0: logger.write("using least squares to solve system", beg="*** ") dw = np.linalg.lstsq(K, b)[0] elif info < 0: raise WasatchError( "illegal value in %d-th argument of internal dposv" % -info) # --- update displacement increment du += relax * dw # --- Check convergence wnorm = np.dot(du, du) err1 = np.dot(dw, dw) if err1 > 1.E-10: findstiff = True if wnorm != 0.: err1 = np.sqrt(err1 / wnorm) err2 = np.sqrt(np.dot(b, b)) / float(ndof * nnode) logger.write_formatted(step + 1, nit + 1, loadfactor, t, dt, err1, err2, tol, fmt=ITER_FMT) if err1 < tol: break continue else: raise WasatchError("Problem did not converge") # Update the total displacecment u += du # Update the nodal coordinates x = np.zeros((nnode, ndof)) for i in range(nnode): for j in range(ndof): x[i, j] = X[i, j] + u[ndof * i + j] continue continue # Advance the state of each element for element in elements: element.advance_state() global_data.set_var("TIME", t) global_data.set_var("TIME_STEP", dt) nodal_data.set_var("DISPL", u) self.io.write_data_to_db() continue self.io.finish() tf = time.time() logger.write("\n{0}: execution finished".format(self.runid)) logger.write("{0}: total execution time: {1:8.6f}s".format( runid, tf - t0)) retval = 0 if disp: retval = { "DISPLACEMENT": u, "TIME": t, "DT": dt, "ELEMENT DATA": np.array([el.element_data() for el in elements]), "NODAL STRESSES": nodal_stresses, # "NODAL STATES": nodal_state, "NODAL COORDINATES": x } return retval
def initialize(eltyp, material): el = elemdb.get(eltyp.upper()) if el: return el(material) raise WasatchError("{0}: element type not recognized".format(eltyp))
def element_class_from_id(eid): for name, el in elemdb.items(): if el.eid == eid: return el raise WasatchError("{0}: unkown element type".format(eid))
def element_class_from_name(name): for clsnam, el in elemdb.items(): if el.name[:3].upper() == name[:3].upper(): return el raise WasatchError("{0}: unkown element type".format(name))
def update_state(self, *args, **kwargs): raise WasatchError("update_state must be provided by model")
def setup(self, pdict): raise WasatchError("setup must be provided by model")
def volume(self, coords): raise WasatchError("Element {0} must define volume".format(self.name))