def __init__(self, anchor, normal, bounds): Struct.__init__(self, anchor=nm.array(anchor, dtype=nm.float64), bounds=nm.asarray(bounds, dtype=nm.float64)) self.normal = nm.asarray(normal, dtype=nm.float64) norm = nm.linalg.norm self.normal /= norm(self.normal) e3 = [0.0, 0.0, 1.0] dd = nm.dot(e3, self.normal) rot_angle = nm.arccos(dd) if nm.abs(rot_angle) < 1e-14: mtx = nm.eye(3, dtype=nm.float64) bounds2d = self.bounds[:, :2] else: rot_axis = nm.cross([0.0, 0.0, 1.0], self.normal) mtx = la.make_axis_rotation_matrix(rot_axis, rot_angle) mm = la.insert_strided_axis(mtx, 0, self.bounds.shape[0]) rbounds = la.dot_sequences(mm, self.bounds) bounds2d = rbounds[:, :2] assert_(nm.allclose(nm.dot(mtx, self.normal), e3, rtol=0.0, atol=1e-12)) self.adotn = nm.dot(self.anchor, self.normal) self.rot_angle = rot_angle self.mtx = mtx self.bounds2d = bounds2d
def get_fargs(self, kappa, virtual, state, mode=None, term_mode=None, diff_var=None, **kwargs): from sfepy.discrete.variables import create_adof_conn, expand_basis geo, _ = self.get_mapping(state) n_el, n_qp, dim, n_en, n_c = self.get_data_shape(virtual) ebf = expand_basis(geo.bf, dim) aux = nm.einsum('i,...ij->...j', kappa, ebf)[0, :, None, :] kebf = insert_strided_axis(aux, 0, n_el) if diff_var is None: econn = state.field.get_econn('volume', self.region) adc = create_adof_conn(nm.arange(state.n_dof, dtype=nm.int32), econn, n_c, 0) vals = state()[adc] aux = dot_sequences(kebf, vals[:, None, :, None]) out_qp = dot_sequences(kebf, aux, 'ATB') fmode = 0 else: out_qp = dot_sequences(kebf, kebf, 'ATB') fmode = 1 return out_qp, geo, fmode
def get_coors(self, ig=None): """ Get the coordinates of vertices of unique facets in group `ig`. Parameters ---------- ig : int, optional The element group. If None, the coordinates for all groups are returned, filled with zeros at places of missing vertices, i.e. where facets having less then the full number of vertices (`n_v`) are. Returns ------- coors : array The coordinates in an array of shape `(n_f, n_v, dim)`. uid : array The unique ids of facets in the order of `coors`. """ cc = self.domain.get_mesh_coors() if ig is None: uid, ii = unique(self.uid_i, return_index=True) facets = self.facets[ii] aux = insert_strided_axis(facets, 2, cc.shape[1]) coors = nm.where(aux >= 0, cc[facets], 0.0) else: uid_i = self.uid_i[self.indx[ig]] uid, ii = unique(uid_i, return_index=True) coors = cc[self.facets[ii, :self.n_fps[ig]]] return coors, uid
def get_coors(self, ig=None): """ Get the coordinates of vertices of unique facets in group `ig`. Parameters ---------- ig : int, optional The element group. If None, the coordinates for all groups are returned, filled with zeros at places of missing vertices, i.e. where facets having less then the full number of vertices (`n_v`) are. Returns ------- coors : array The coordinates in an array of shape `(n_f, n_v, dim)`. uid : array The unique ids of facets in the order of `coors`. """ cc = self.domain.get_mesh_coors() if ig is None: uid, ii = unique(self.uid_i, return_index=True) facets = self.facets[ii] aux = insert_strided_axis(facets, 2, cc.shape[1]) coors = nm.where(aux >= 0, cc[facets], 0.0) else: uid_i = self.uid_i[self.indx[ig]] uid, ii = unique(uid_i, return_index=True) coors = cc[self.facets[ii,:self.n_fps[ig]]] return coors, uid
def get_fargs(self, kappa, kvar, dvar, mode=None, term_mode=None, diff_var=None, **kwargs): from sfepy.discrete.variables import create_adof_conn, expand_basis geo, _ = self.get_mapping(dvar) n_el, n_qp, dim, n_en, n_c = self.get_data_shape(kvar) ebf = expand_basis(geo.bf, dim) aux = nm.einsum('i,...ij->...j', kappa, ebf)[0, :, None, :] kebf = insert_strided_axis(aux, 0, n_el) div_bf = geo.bfg div_bf = div_bf.reshape((n_el, n_qp, 1, dim * n_en)) div_bf = nm.ascontiguousarray(div_bf) if diff_var is None: avar = dvar if self.mode == 'kd' else kvar econn = avar.field.get_econn('volume', self.region) adc = create_adof_conn(nm.arange(avar.n_dof, dtype=nm.int32), econn, n_c, 0) vals = avar()[adc] if self.mode == 'kd': aux = dot_sequences(div_bf, vals[:, None, :, None]) out_qp = dot_sequences(kebf, aux, 'ATB') else: aux = dot_sequences(kebf, vals[:, None, :, None]) out_qp = dot_sequences(div_bf, aux, 'ATB') fmode = 0 else: if self.mode == 'kd': out_qp = dot_sequences(kebf, div_bf, 'ATB') else: out_qp = dot_sequences(div_bf, kebf, 'ATB') fmode = 1 return out_qp, geo, fmode
def test_tensors(self): import numpy as nm from sfepy.linalg import dot_sequences, insert_strided_axis ok = True a = nm.arange(1, 10).reshape(3, 3) b = nm.arange(9, 0, -1).reshape(3, 3) dab = nm.dot(a, b) dabt = nm.dot(a, b.T) datb = nm.dot(a.T, b) datbt = nm.dot(a.T, b.T) sa = insert_strided_axis(a, 0, 10) sb = insert_strided_axis(b, 0, 10) dsab = dot_sequences(sa, sb, mode='AB') _ok = nm.allclose(dab[None, ...], dsab, rtol=0.0, atol=1e-14) self.report('dot_sequences AB: %s' % _ok) ok = ok and _ok dsabt = dot_sequences(sa, sb, mode='ABT') _ok = nm.allclose(dabt[None, ...], dsabt, rtol=0.0, atol=1e-14) self.report('dot_sequences ABT: %s' % _ok) ok = ok and _ok dsatb = dot_sequences(sa, sb, mode='ATB') _ok = nm.allclose(datb[None, ...], dsatb, rtol=0.0, atol=1e-14) self.report('dot_sequences ATB: %s' % _ok) ok = ok and _ok dsatbt = dot_sequences(sa, sb, mode='ATBT') _ok = nm.allclose(datbt[None, ...], dsatbt, rtol=0.0, atol=1e-14) self.report('dot_sequences ATBT: %s' % _ok) ok = ok and _ok return ok
def _eval_base(self, coors, diff=False, ori=None, suppress_errors=False, eps=1e-15): """ See PolySpace.eval_base(). """ from extmods.lobatto_bases import eval_lobatto_tensor_product as ev c_min, c_max = self.bbox[:, 0] base = ev(coors, self.nodes, c_min, c_max, self.order, diff) if ori is not None: ebase = nm.tile(base, (ori.shape[0], 1, 1, 1)) if self.edge_indx.shape[0]: # Orient edge functions. ie, ii = nm.where(ori[:, self.edge_indx] == 1) ii = self.edge_indx[ii] ebase[ie, :, :, ii] *= -1.0 if self.face_indx.shape[0]: # Orient face functions. fori = ori[:, self.face_indx] # ... normal axis order ie, ii = nm.where((fori == 1) | (fori == 2)) ii = self.face_indx[ii] ebase[ie, :, :, ii] *= -1.0 # ... swapped axis order sbase = ev(coors, self.sfnodes, c_min, c_max, self.order, diff) sbase = insert_strided_axis(sbase, 0, ori.shape[0]) # ...overwrite with swapped axes basis. ie, ii = nm.where(fori >= 4) ii2 = self.face_indx[ii] ebase[ie, :, :, ii2] = sbase[ie, :, :, ii] # ...deal with orientation. ie, ii = nm.where((fori == 5) | (fori == 6)) ii = self.face_indx[ii] ebase[ie, :, :, ii] *= -1.0 base = ebase return base
def _eval_base(self, coors, diff=False, ori=None, suppress_errors=False, eps=1e-15): """ See PolySpace.eval_base(). """ from .extmods.lobatto_bases import eval_lobatto_tensor_product as ev c_min, c_max = self.bbox[:, 0] base = ev(coors, self.nodes, c_min, c_max, self.order, diff) if ori is not None: ebase = nm.tile(base, (ori.shape[0], 1, 1, 1)) if self.edge_indx.shape[0]: # Orient edge functions. ie, ii = nm.where(ori[:, self.edge_indx] == 1) ii = self.edge_indx[ii] ebase[ie, :, :, ii] *= -1.0 if self.face_indx.shape[0]: # Orient face functions. fori = ori[:, self.face_indx] # ... normal axis order ie, ii = nm.where((fori == 1) | (fori == 2)) ii = self.face_indx[ii] ebase[ie, :, :, ii] *= -1.0 # ... swapped axis order sbase = ev(coors, self.sfnodes, c_min, c_max, self.order, diff) sbase = insert_strided_axis(sbase, 0, ori.shape[0]) # ...overwrite with swapped axes basis. ie, ii = nm.where(fori >= 4) ii2 = self.face_indx[ii] ebase[ie, :, :, ii2] = sbase[ie, :, :, ii] # ...deal with orientation. ie, ii = nm.where((fori == 5) | (fori == 6)) ii = self.face_indx[ii] ebase[ie, :, :, ii] *= -1.0 base = ebase return base
def mask_points(self, points): mm = la.insert_strided_axis(self.mtx, 0, points.shape[0]) points2d = la.dot_sequences(mm, points)[:, :2] return la.flag_points_in_polygon2d(self.bounds2d, points2d)
def describe_deformation(el_disps, bfg): """ Describe deformation of a thin incompressible 2D membrane in 3D space, composed of flat finite element faces. The coordinate system of each element (face), i.e. the membrane mid-surface, should coincide with the `x`, `y` axes of the `x-y` plane. Parameters ---------- el_disps : array The displacements of element nodes, shape `(n_el, n_ep, dim)`. bfg : array The in-plane base function gradients, shape `(n_el, n_qp, dim-1, n_ep)`. Returns ------- mtx_c ; array The in-plane right Cauchy-Green deformation tensor :math:`C_{ij}`, :math:`i, j = 1, 2`. c33 : array The component :math:`C_{33}` computed from the incompressibility condition. mtx_b : array The discrete Green strain variation operator. """ sh = bfg.shape n_ep = sh[3] dim = el_disps.shape[2] sym2 = dim2sym(dim-1) # Repeat el_disps by number of quadrature points. el_disps_qp = insert_strided_axis(el_disps, 1, bfg.shape[1]) # Transformed (in-plane) displacement gradient with # shape (n_el, n_qp, 2 (-> a), 3 (-> i)), du_i/dX_a. du = dot_sequences(bfg, el_disps_qp) # Deformation gradient F w.r.t. in plane coordinates. # F_{ia} = dx_i / dX_a, # a \in {1, 2} (rows), i \in {1, 2, 3} (columns). mtx_f = du + nm.eye(dim - 1, dim, dtype=du.dtype) # Right Cauchy-Green deformation tensor C. # C_{ab} = F_{ka} F_{kb}, a, b \in {1, 2}. mtx_c = dot_sequences(mtx_f, mtx_f, 'ABT') # C_33 from incompressibility. c33 = 1.0 / (mtx_c[..., 0, 0] * mtx_c[..., 1, 1] - mtx_c[..., 0, 1]**2) # Discrete Green strain variation operator. mtx_b = nm.empty((sh[0], sh[1], sym2, dim * n_ep), dtype=nm.float64) mtx_b[..., 0, 0*n_ep:1*n_ep] = bfg[..., 0, :] * mtx_f[..., 0, 0:1] mtx_b[..., 0, 1*n_ep:2*n_ep] = bfg[..., 0, :] * mtx_f[..., 0, 1:2] mtx_b[..., 0, 2*n_ep:3*n_ep] = bfg[..., 0, :] * mtx_f[..., 0, 2:3] mtx_b[..., 1, 0*n_ep:1*n_ep] = bfg[..., 1, :] * mtx_f[..., 1, 0:1] mtx_b[..., 1, 1*n_ep:2*n_ep] = bfg[..., 1, :] * mtx_f[..., 1, 1:2] mtx_b[..., 1, 2*n_ep:3*n_ep] = bfg[..., 1, :] * mtx_f[..., 1, 2:3] mtx_b[..., 2, 0*n_ep:1*n_ep] = bfg[..., 1, :] * mtx_f[..., 0, 0:1] \ + bfg[..., 0, :] * mtx_f[..., 1, 0:1] mtx_b[..., 2, 1*n_ep:2*n_ep] = bfg[..., 0, :] * mtx_f[..., 1, 1:2] \ + bfg[..., 1, :] * mtx_f[..., 0, 1:2] mtx_b[..., 2, 2*n_ep:3*n_ep] = bfg[..., 0, :] * mtx_f[..., 1, 2:3] \ + bfg[..., 1, :] * mtx_f[..., 0, 2:3] return mtx_c, c33, mtx_b