def test_csys(self): from spyfe.csys import CSys from numpy import linalg assert CSys().isconstant assert CSys().isidentity q, r = linalg.qr(numpy.random.rand(3, 3)) assert CSys(matrix=q).isidentity == False
def __init__(self, fes=None, integration_rule=None, material_csys=CSys(), assoc_geom=None): self.fes = None self.fes = fes self.integration_rule = integration_rule self.material_csys = material_csys self.assoc_geom = assoc_geom
def __init__(self, fes=None, integration_rule=None, material_csys=CSys(), assoc_geom=None, material=None): """Constructor. :param material: Material object. :param fes: Finite element set object. :param integration_rule: Integration rule object. """ super().__init__(fes=fes, integration_rule=integration_rule, material_csys=material_csys, assoc_geom=assoc_geom) self.material = material
def plot_stress(model_data): """Algorithm for plotting stress results. :param model_data: Model data dictionary. model_data['fens'] = finite element node set (mandatory) For each region (connected piece of the domain made of a particular material), mandatory: model_data['regions']= list of dictionaries, one for each region Each region: region['femm'] = finite element set that covers the region (mandatory) For essential boundary conditions (optional): model_data['boundary_conditions']['essential']=list of dictionaries, one for each application of an essential boundary condition. For each EBC dictionary ebc: ebc['node_list'] = node list, ebc['comp'] = displacement component (zero-based), ebc['value'] = function to supply the prescribed value, default is lambda x: 0.0 :return: Success? True or false. The model_data object is modified. model_data['geom'] =the nodal field that is the geometry model_data['temp'] =the nodal field that is the computed temperature model_data['timings'] = timing of the individual operations """ file = 'stresses' if 'postprocessing' in model_data: if 'file' in model_data['postprocessing']: file = model_data['postprocessing']['file'] outcs = model_data['postprocessing']['outcs'] if 'outcs' in model_data['postprocessing']\ else CSys() geom = model_data['geom'] u = model_data['u'] dtemp = model_data['dtemp'] if 'dtemp' in model_data else None for r in range(len(model_data['regions'])): region = model_data['regions'][r] femm = region['femm'] stresses = femm.nodal_field_from_integr_points( geom, u, u, dtempn1=dtemp, output=OUTPUT_CAUCHY, component=[0, 1, 2, 3, 4, 5], outcs=outcs) vtkexport(file + str(r), femm.fes, model_data['geom'], { 'displacement': u, 'stresses': stresses }) return True
def __init__(self, material=None, fes=None, integration_rule=None, material_csys=CSys(), assoc_geom=None): """Constructor. :param material: Material object. :param fes: Finite element set object. :param integration_rule: Integration rule object. """ integration_rule = TetRule(npts=4) if integration_rule is None else integration_rule super().__init__(fes=fes, material=material, integration_rule=integration_rule, material_csys=material_csys, assoc_geom=assoc_geom) self._gamma = 2.6 #one of the stabilization parameters self._C = 1.e4 #the other stabilization parameter
def __init__(self, material=None, fes=None, integration_rule=None, material_csys=CSys(), assoc_geom=None): """Constructor. :param material: Material object. :param fes: Finite element set object. :param integration_rule: Integration rule object. """ super().__init__(fes=fes, integration_rule=integration_rule, material_csys=material_csys, assoc_geom=assoc_geom) self.material = material self._phis = None e = getattr(self.material, 'e', None) if e is not None: e = self.material.e if self.material.nu < 0.3: nu = self.material.nu else: nu = 0.3 + (self.material.nu - 0.3) / 2.0 else: e1 = getattr(self.material, 'e1', None) if e1 is not None: e = min(self.material.e1, self.material.e2, self.material.e3) nu = min(self.material.nu12, self.material.nu13, self.material.nu23) else: raise Exception( 'No clues on how to construct the stabilization material') self.stabilization_material = MatDeforTriaxLinearIso(e=e, nu=nu) # Now try to figure out which Poisson ratio to use in the optimal scaling # factor(to account for geometry) nu = getattr(self.material, "nu", None) if nu is not None: self.nu = self.material.nu else: nu12 = getattr(self.material, "nu12", None) if nu12 is not None: self.nu = max(self.material.nu12, self.material.nu13, self.material.nu23) else: raise Exception( 'No clues on how to construct the stabilization material')
def nodal_field_from_integr_points(self, geom, un1, un, dt=0.0, dtempn1=None, outcs=CSys(), output=OUTPUT_CAUCHY, component=(0,)): """Create a nodal field from quantities at integration points. The procedure is the universe-distance interpolation. :param geom: Geometry field. :param un1: Displacement field at the time t_n+1. :param un: Displacement field at time t_n. :param dt: Time step from t_n to t_n+1. :param dtempn1: Temperature increment field or None. :param outcs: Output coordinate system. :param output: Output quantity (enumeration). :param component: Which component of the output quantity? :return: nodal field """ # Container of intermediate results sum_inv_dist = numpy.zeros((geom.nfens,)) sum_quant_inv_dist = numpy.zeros((geom.nfens, len(component))) fld = NodalField(nfens=geom.nfens, dim=len(component)) # This is an inverse-distance interpolation inspector. def idi(idat, out, xyz, u, pc): x, conn = idat da = x - numpy.ones((x.shape[0], 1)) * xyz d = numpy.sum(da ** 2, axis=1) zi = d == 0 d[zi] = min(d[~zi]) / 1.e9 invd = numpy.reshape(1. / d, (x.shape[0], 1)) quant = numpy.reshape(out[component], (1, len(component))) sum_quant_inv_dist[conn, :] += invd * quant sum_inv_dist[conn] += invd.ravel() return # Loop over cells to interpolate to nodes for i in range(self.fes.conn.shape[0]): x1 = geom.values[self.fes.conn[i, :], :] idat1 = (x1, self.fes.conn[i, :]) self.inspect_integration_points([i], idi, idat1, geom, un1, un, dt, dtempn1, outcs, output) # compute the field data array nzi = ~(sum_inv_dist == 0) for j in range(len(component)): fld.values[nzi, j] = sum_quant_inv_dist[nzi, j] / sum_inv_dist[nzi] return fld
def __init__(self, material=None, fes=None, integration_rule=None, material_csys=CSys(), assoc_geom=None): """Constructor. :param material: Material object. :param fes: Finite element set object. :param integration_rule: Integration rule object. """ integration_rule = GaussRule( dim=3, order=2) if integration_rule is None else integration_rule super().__init__(fes=fes, material=material, integration_rule=integration_rule, material_csys=material_csys, assoc_geom=assoc_geom)
def inspect_integration_points(self, fe_list, inspector, idat, geom, un1, un, dt=0.0, dtempn1=None, outcs=CSys(), output=OUTPUT_CAUCHY): """Inspect integration point quantities. :param fe_list: indexes of the finite elements that are to be inspected: The fes to be included are: fes.conn[fe_list, :]. :param inspector: inspector function, :param idat: data for inspector function, :param geom: Geometry field. :param un1: Displacement field at the time t_n+1. :param un: Displacement field at time t_n. :param dt: Time step from t_n to t_n+1. :param dtempn1: Temperature increment field or None. :param outcs: output coordinate system :param output: type of output :return: idat: data for inspector function """ raise Exception( 'This method needs to be overridden in the derived class') # need to override in the child class
def __init__(self, material=None, fes=None, integration_rule=None, material_csys=CSys(), assoc_geom=None, surface_normal_spring_coefficient=1.0, surface_normal=None): """Constructor. :param material: Material object. :param fes: Finite element set object. :param integration_rule: Integration rule object. """ super().__init__(fes=fes, integration_rule=integration_rule, material_csys=material_csys, assoc_geom=assoc_geom) self.surface_normal_spring_coefficient = surface_normal_spring_coefficient self.surface_normal = surface_normal
def elemental_field_from_integr_points(self, geom, un1, un, dt=0.0, dtempn1=None, outcs=CSys(), output=OUTPUT_CAUCHY, component=(0,)): """Create a elemental field from quantities at integration points. :param geom: Geometry field. :param un1: Displacement field at the time t_n+1. :param un: Displacement field at time t_n. :param dt: Time step from t_n to t_n+1. :param dtempn1: Temperature increment field or None. :param outcs: Output coordinate system. :param output: Output quantity (enumeration). :param component: Which component of the output quantity? :return: nodal field """ # Container of intermediate results nelems = self.fes.conn.shape[0] n_q = numpy.zeros((nelems,)) sum_q = numpy.zeros((nelems, len(component))) fld = ElementalField(nelems=nelems, dim=len(component)) # This is an inverse-distance interpolation inspector. def idi(idat, out, xyz, u, pc): i = idat quant = numpy.reshape(out[component], (1, len(component))) sum_q[i, :] += quant.ravel() n_q[i] += 1 return # Loop over cells to interpolate to nodes for i in range(self.fes.conn.shape[0]): x1 = geom.values[self.fes.conn[i, :], :] idat1 = i self.inspect_integration_points([i], idi, idat1, geom, un1, un, dt, dtempn1, outcs, output) # compute the field data array for i in range(self.fes.conn.shape[0]): for j in range(len(component)): fld.values[i, j] = sum_q[i, j] / n_q[i] return fld
def elem_dep_data_qt10ms(na, nb, nts): print(na, nb, nts) # fens, fes = t4_block(a, b, t, na, nb, nt, orientation='a') fens, fes = t4_composite_plate(a, b, ts, na, nb, nts) fens, fes = t4_to_t10(fens, fes) bfes = mesh_boundary(fes) t = sum(ts) fesel = fe_select(fens, bfes, box=[0, a, 0, b, t, t], inflate=htol) tsfes = bfes.subset(fesel) femms = [] for layer in range(len(nts)): aangle = angles[layer] / 180. * math.pi print(aangle) mcsys = CSys(matrix=rotmat(numpy.array([0.0, 0.0, aangle]))) el = fe_select(fens, fes, bylabel=True, label=layer) femms.append( FEMMDeforLinearQT10MS(material=m, material_csys=mcsys, fes=fes.subset(el))) sfemm = FEMMDeforLinear(fes=tsfes, integration_rule=TriRule(npts=3)) return fens, femms, sfemm
aangle = 45.0 / 180. * math.pi uz_ref = -1.202059060799316e-06 * SI.m a, b, t = 90.0 * SI.mm, 100.0 * SI.mm, 20.0 * SI.mm na, nb, nt = 6, 6, 2 htol = min(a, b, t) / 1000 q0 = -1. * SI.psi m = MatDeforTriaxLinearOrtho(e1=e1, e2=e2, e3=e3, g12=g12, g13=g13, g23=g23, nu12=nu12, nu13=nu13, nu23=nu23) mcsys = CSys(matrix=rotmat(numpy.array([0.0, 0.0, aangle]))) def elem_dep_data_t10(na, nb, nt): fens, fes = t4_block(a, b, t, na, nb, nt, orientation='a') fens, fes = t4_to_t10(fens, fes) femm = FEMMDeforLinear(material=m, material_csys=mcsys, fes=fes, integration_rule=TetRule(npts=4)) bfes = mesh_boundary(femm.fes) fesel = fe_select(fens, bfes, box=[a, a, 0, b, 0, t], inflate=htol) tsfes = bfes.subset(fesel) sfemm = FEMMDeforLinear(fes=tsfes, integration_rule=TriRule(npts=3)) return fens, femm, sfemm
model_data['boundary_conditions']['essential'] = essential # Traction on the free end fi = ForceIntensity(magn=lambda x, J: numpy.array([0, 0, q0])) traction = [{'femm': sfemm, 'force_intensity': fi}] model_data['boundary_conditions']['traction'] = traction # Call the solver algo_defor_linear.statics(model_data) # for action, time in model_data['timings']: # print(action, time, ' sec') geom = model_data['geom'] u = model_data['u'] bottom_edge = fenode_select( fens, box=[a / 2.0, a / 2.0, b / 2.0, b / 2.0, 0, t], inflate=htol) uv = u.values[bottom_edge, :] uz = numpy.mean(abs(uv[:, 2])) print('Center displacement uz =', uz, ', ', (uz / abs(wc_analytical) * 100), ' %') algo_defor_linear.plot_displacement(model_data) model_data['postprocessing'] = { 'file': 'Z_laminate_u_ss_' + k + '_results', 'outcs': CSys() } # algo_defor.plot_stress(model_data) algo_defor.plot_elemental_stress(model_data)
def inspect_integration_points(self, fe_list, inspector, idat, geom, un1, un, dt=0.0, dtempn1=None, outcs=CSys(), output=OUTPUT_CAUCHY): """Inspect integration point quantities. :param fe_list: indexes of the finite elements that are to be inspected: The fes to be included are: fes.conn[fe_list, :]. :param inspector: inspector function, :param idat: data for inspector function, :param geom: Geometry field. :param un1: Displacement field at the time t_n+1. :param un: Displacement field at time t_n. :param dt: Time step from t_n to t_n+1. :param dtempn1: Temperature increment field or None. :return: idat: data for inspector function """ fes = self.fes bfuns, gradbfunpars, npts, pc, w = self.integration_data() mcs = self.material_csys if mcs.isconstant: mcsmtx = mcs.eval_matrix() # constant if outcs is not None and outcs.isconstant: outcsmtx = outcs.eval_matrix() # constant if dtempn1 is None: dtemps = numpy.zeros((geom.nfens, 1)) else: dtemps = dtempn1.values bmatfun, bbar = self.fes.bmatdata(self.fes.nfens) elemu = numpy.zeros((fes.nfens * un1.dim, )) gradbfun = list() jac = list() gradbfunmean = numpy.zeros((fes.nfens, geom.dim)) for j in range(npts): gradbfun.append(numpy.zeros((fes.nfens, geom.dim))) jac.append(0.0) quantityout = None vout = None for i in fe_list: x = geom.values[fes.conn[i, :], :] # Calculate mean basis function gradient + volume of the element vol = 0 gradbfunmean.fill(0.0) for j in range(npts): jacmat = dot(x.T, gradbfunpars[j]) jac[j] = fes.jac_volume(fes.conn[i, :], bfuns[j], jacmat, x) fes.gradbfun(gradbfun[j], gradbfunpars[j], jacmat) dvol = jac[j] * w[j] gradbfunmean += gradbfun[j] * dvol vol = vol + dvol gradbfunmean /= vol bmatfun(bbar, None, gradbfunmean, None) un1.gather_values_vec(fes.conn[i, :], elemu) c = dot(bfuns[j].T, x) # Model location of the quadrature point u_c = dot(bfuns[j].T, un1.values[fes.conn[ i, :], :]) # Displacement of the quad point strain = dot(bbar, elemu) # strain in global Cartesian coordinate system mstrain = numpy.copy(strain) #strain in material coordinate # If necessary, transform the strain from the global CS to the material CS if not mcs.isidentity: # Transformation is required if not mcs.isconstant: # Do I need to evaluate the local mat orient? mcsmtx = mcs.eval_matrix(c, jacmat, fes.label[i]) self.material.rotate_strain_vector(mstrain, mcsmtx, strain) dtemp = dot(bfuns[j].T, dtemps[fes.conn[i, :]]) quantityout = self.material.state(None, strain=strain, dtemp=dtemp, output=output, quantityout=quantityout) if output == OUTPUT_CAUCHY: # vector quantity: transformation may be required if vout is None: vout = numpy.zeros_like(quantityout) if not mcs.isidentity: # Transformation is required self.material.rotate_stress_vector(vout, mcsmtx.T, quantityout) quantityout[:] = vout[:] if not outcs.isidentity: # Transformation is required if not outcs.isconstant: # Do I need to evaluate the local mat orient? outcsmtx = outcs.eval_matrix(c, jacmat, fes.label[i]) self.material.rotate_stress_vector(vout, outcsmtx, quantityout) quantityout[:] = vout[:] else: # pass if inspector is not None: inspector(idat, quantityout, c, u_c, pc[j, :]) return idat
def nodal_field_from_integr_points_spr(self, geom, un1, un, dt=0.0, dtempn1=None, outcs=CSys(), output=OUTPUT_CAUCHY, component=(0,)): """Create a nodal field from quantities at integration points. The procedure is the Super-convergent Patch Recovery. :param geom: Geometry field. :param un1: Displacement field at the time t_n+1. :param un: Displacement field at time t_n. :param dt: Time step from t_n to t_n+1. :param dtempn1: Temperature increment field or None. :param outcs: Output coordinate system. :param output: Output quantity (enumeration). :param component: Which component of the output quantity? :return: nodal field """ fes = self.fes # Make the inverse map from finite element nodes to finite elements femap = fenode_to_fe_map(geom.nfens, fes.conn) fld = NodalField(nfens=geom.nfens, dim=len(component)) # This is an inverse-distance interpolation inspector. def idi(idat, out, xyz, u, pc): idat.append((numpy.array(out), xyz)) def spr(idat, xc): """Super-convergent Patch Recovery. :param idat: List of integration point data. :param xc: Location at which the quantities to be recovered. :return: Recovered quantity. """ n = len(idat) if n == 0: # nothing can be done raise Exception('No data for SPR') elif n == 1: # we got a single value: return it out, xyz = idat[0] sproutput = out.ravel() / n else: # attempt to solve the least-squares problem out, xyz = idat[0] dim = xyz.size # the number of modeling dimensions (1, 2, 3) nc = out.size na = dim + 1 if (n >= na): A = numpy.zeros((na, na)) b = numpy.zeros((na, nc)) pk = numpy.zeros((na, 1)) pk[0] = 1.0 for k in range(n): out, xyz = idat[k] out.shape = (1, nc) xk = xyz - xc pk[1:] = xk[:].reshape(dim, 1) A += pk * pk.T b += pk * out try: a = numpy.linalg.solve(A, b) # xk = xc - xc # p = [1, xk] sproutput = a[0, :].ravel() except: # not enough to solve the least-squares problem: compute simple average out, xyz = idat[0] sproutput = out / n for k in range(1, n): out, xyz = idat[k] sproutput += out / n sproutput = sproutput.ravel() else: # not enough to solve the least-squares problem: compute simple average out, xyz = idat[0] sproutput = out / n for k in range(1, n): out, xyz = idat[k] sproutput += out / n sproutput = sproutput.ravel() return sproutput # Loop over nodes, and for each visit the connected FEs for i in range(geom.nfens): idat = [] xc = geom.values[i, :] # location of the current node # construct the list of the relevant integr points # and the values at these points idat = self.inspect_integration_points(femap[i], idi, idat, geom, un1, un, dt, dtempn1, outcs, output) out1 = spr(idat, xc) fld.values[i, :] = out1[:] return fld
aangle = 30.0 / 180. * math.pi uz_ref = -1.054995121951226e-02 * SI.mm #millimeters a, b, t = 90.0 * SI.mm, 10.0 * SI.mm, 20.0 * SI.mm #millimeters # na, nb, nt = 16, 4,4 htol = min(a, b, t) / 1000 magn = -1000. * SI.Pa # Pascal m = MatDeforTriaxLinearOrtho(e1=e1, e2=e2, e3=e3, g12=g12, g13=g13, g23=g23, nu12=nu12, nu13=nu13, nu23=nu23) mcsys = CSys(matrix=rotmat(numpy.array([aangle, aangle, aangle]))) def elem_dep_data_t10(na, nb, nt): fens, fes = t4_block(a, b, t, na, nb, nt, orientation='a') fens, fes = t4_to_t10(fens, fes) femm = FEMMDeforLinear(material=m, material_csys=mcsys, fes=fes, integration_rule=TetRule(npts=4)) bfes = mesh_boundary(femm.fes) fesel = fe_select(fens, bfes, box=[a, a, 0, b, 0, t], inflate=htol) tsfes = bfes.subset(fesel) sfemm = FEMMDeforLinear(fes=tsfes, integration_rule=TriRule(npts=3)) return fens, femm, sfemm