def _standard_call(self, rhs, x0=None, conf=None, eps_a=None, eps_r=None, i_max=None, mtx=None, status=None, context=None, **kwargs): tt = time.clock() conf = get_default(conf, self.conf) mtx = get_default(mtx, self.mtx) status = get_default(status, self.status) context = get_default(context, self.context) assert_(mtx.shape[0] == mtx.shape[1] == rhs.shape[0]) if x0 is not None: assert_(x0.shape[0] == rhs.shape[0]) result = call(self, rhs, x0, conf, eps_a, eps_r, i_max, mtx, status, context=context, **kwargs) if isinstance(result, tuple): result, n_iter = result else: n_iter = -1 # Number of iterations is undefined/unavailable. ttt = time.clock() - tt if status is not None: status['time'] = ttt status['n_iter'] = n_iter return result
def get_constants(ts=None, coors=None, mode=None, term=None, problem=None, **kwargs): out = {} if mode == 'qp': qps = term.get_physical_qps() assert_(qps.num == coors.shape[0]) for key, val in six.iteritems(values): if '.' in key: continue rval = nm.array(val[list(val.keys())[0]], dtype=nm.float64, ndmin=3) s0 = rval.shape[1:] matdata = nm.zeros(qps.shape[:2] + s0, dtype=nm.float64) for rkey, rval in six.iteritems(val): region = problem.domain.regions[rkey] rval = nm.array(rval, dtype=nm.float64, ndmin=3) cells = region.get_cells(true_cells_only=False) ii = term.region.get_cell_indices(cells, true_cells_only=False) matdata[ii] = rval out[key] = matdata.reshape((-1,) + s0) return out
def create_petsc_system(mtx, sizes, pdofs, drange, is_overlap=True, comm=None, verbose=False): """ Create and pre-allocate (if `is_overlap` is True) a PETSc matrix and related solution and right-hand side vectors. """ if comm is None: comm = PETSc.COMM_WORLD if is_overlap: mtx.data[:] = 1 mtx_prealloc = create_prealloc_data(mtx, pdofs, drange, verbose=True) pmtx = create_petsc_matrix(sizes, mtx_prealloc, comm=comm) else: pmtx = create_petsc_matrix(sizes, comm=comm) own_range = pmtx.getOwnershipRange() output('pmtx ownership:', own_range, verbose=verbose) assert_(own_range == drange) psol, prhs = pmtx.getVecs() own_range = prhs.getOwnershipRange() output('prhs ownership:', own_range, verbose=verbose) assert_(own_range == drange) return pmtx, psol, prhs
def _petsc_call(self, rhs, x0=None, conf=None, eps_a=None, eps_r=None, i_max=None, mtx=None, status=None, comm=None, context=None, **kwargs): tt = time.clock() conf = get_default(conf, self.conf) mtx = get_default(mtx, self.mtx) status = get_default(status, self.status) context = get_default(context, self.context) comm = get_default(comm, self.comm) mshape = mtx.size if isinstance(mtx, self.petsc.Mat) else mtx.shape rshape = [rhs.size] if isinstance(rhs, self.petsc.Vec) else rhs.shape assert_(mshape[0] == mshape[1] == rshape[0]) if x0 is not None: xshape = [x0.size] if isinstance(x0, self.petsc.Vec) else x0.shape assert_(xshape[0] == rshape[0]) result = call(self, rhs, x0, conf, eps_a, eps_r, i_max, mtx, status, comm, context=context, **kwargs) ttt = time.clock() - tt if status is not None: status['time'] = ttt status['n_iter'] = self.ksp.getIterationNumber() return result
def set_dofs(self, fun=0.0, region=None, dpn=None, warn=None): """ Set the values of given DOFs using a function of space coordinates or value `fun`. Notes ----- Works for a constant value over an entire patch side only. """ if region is None: region = self.region if dpn is None: dpn = self.n_components nods = [] vals = [] aux = self.get_dofs_in_region(region, clean=True, warn=warn) nods = nm.unique(nm.hstack(aux)) if nm.isscalar(fun): vals = nm.repeat([fun], nods.shape[0] * dpn) elif isinstance(fun, nm.ndarray): assert_(len(fun) == dpn) vals = nm.repeat(fun, nods.shape[0]) else: raise ValueError('unknown function/value type! (%s)' % type(fun)) return nods, vals
def insert_sparse_to_csr(mtx1, mtx2, irs, ics): """ Insert a sparse matrix `mtx2` into a CSR sparse matrix `mtx1` at rows `irs` and columns `ics`. The submatrix `mtx1[irs,ics]` must already be preallocated and have the same structure as `mtx2`. """ import sfepy.discrete.common.extmods.assemble as asm if isinstance(irs, slice): irs = nm.arange(irs.start, irs.stop, irs.step, dtype=nm.int32) if isinstance(ics, slice): ics = nm.arange(ics.start, ics.stop, ics.step, dtype=nm.int32) n_row, n_col = mtx1.shape assert_((irs.min() >= 0) and (irs.max() < n_row)) assert_((ics.min() >= 0) and (ics.max() < n_col)) aux = mtx2.tocoo() data = nm.ascontiguousarray(aux.data[:,None,None,None]) rows = irs[aux.row[:,None]] cols = ics[aux.col[:,None]] iels = nm.arange(rows.shape[0], dtype=nm.int32) asm.assemble_matrix(mtx1.data, mtx1.indptr, mtx1.indices, data, iels, 1.0, rows, cols)
def compute_bezier_extraction(knots, degrees): """ Compute local (element) Bezier extraction operators for a nD B-spline parametric domain. Parameters ---------- knots : sequence of array or array The knot vectors. degrees : sequence of ints or int Polynomial degrees in each parametric dimension. Returns ------- cs : list of lists of 2D arrays The element extraction operators in each parametric dimension. """ if isinstance(degrees, int): degrees = [degrees] knots = _get_knots_tuple(knots) dim = len(knots) assert_(dim == len(degrees)) cs = [] for ii, knots1d in enumerate(knots): cs1d = compute_bezier_extraction_1d(knots1d, degrees[ii]) cs.append(cs1d) return cs
def get_poly(order, dim, is_simplex=False): """ Construct a polynomial of given `order` in space dimension `dim`, and integrate it symbolically over a rectangular or simplex domain for coordinates in [0, 1]. """ xs = symarray("x", dim) opd = max(1, int((order + 1) / dim)) poly = 1.0 oo = 0 for ii, x in enumerate(xs): if ((oo + opd) > order) or (ii == (len(xs) - 1)): opd = max(order - oo, 0) poly *= x ** opd + 1 oo += opd assert_(oo == order) limits = [[xs[ii], 0, 1] for ii in range(dim)] if is_simplex: for ii in range(1, dim): for ip in range(0, ii): limits[ii][2] -= xs[ip] integral = sm.integrate(poly, *reversed(limits)) return xs, poly, limits, integral
def __call__(self, parser, namespace, value, option_string=None): vals = value.split(',') assert_(len(vals) in [2, 3, 6]) val = tuple(float(ii) for ii in vals) if len(vals) == 6: val = val[:3] + (list(val[3:]),) setattr(namespace, self.dest, val)
def postprocess(filename_input, filename_results, options): """ Postprocess probe data files - replot, integrate data. """ from matplotlib import pyplot as plt header, results = read_results(filename_input, only_names=options.only_names) output(header) fig = plt.figure() for name, result in results.iteritems(): pars, vals = result[:, 0], result[:, 1] ii = nm.where(nm.isfinite(vals))[0] # Nans only at the edges. assert_(nm.diff(ii).sum() == (len(ii)-1)) val = integrate_along_line(pars[ii], vals[ii], options.radial) label = r'%s: $\int\ %s' % (name, name) if options.radial: label += ' (r)' label += '$ = %.5e'% val plt.plot(pars, vals, label=label, lw=0.2, marker='+', ms=1) plt.ylabel('probed data') plt.xlabel('probe coordinate') output(label) plt.legend() fig.savefig(filename_results)
def test_material_functions(self): from sfepy.discrete import Material problem = self.problem conf = problem.conf ts = problem.get_default_ts(step=0) conf_mat1 = conf.get_item_by_name('materials', 'mf1') mat1 = Material.from_conf(conf_mat1, problem.functions) mat1.time_update(ts, None, mode='normal', problem=problem) coors = problem.domain.get_mesh_coors() assert_(nm.all(coors[:,0] == mat1.get_data(None, 'x_0'))) conf_mat2 = conf.get_item_by_name('materials', 'mf2') mat2 = Material.from_conf(conf_mat2, problem.functions) mat2.time_update(ts, None, mode='normal', problem=problem) assert_(nm.all(coors[:,1] == mat2.get_data(None, 'x_1'))) materials = problem.get_materials() materials.time_update(ts, problem.equations, mode='normal', problem=problem) mat3 = materials['mf3'] key = mat3.get_keys(region_name='Omega')[0] assert_(nm.all(mat3.get_data(key, 'a') == 10.0)) assert_(nm.all(mat3.get_data(key, 'b') == 2.0)) assert_(mat3.get_data(None, 'c') == 'ahoj') return True
def compute_cat( self, ret_iw_dir=False ): """Compute the Christoffel acoustic tensor, given the incident wave direction.""" opts = self.app_options iw_dir = nm.array( opts.incident_wave_dir, dtype = nm.float64 ) dim = self.problem.get_dim() assert_( dim == iw_dir.shape[0] ) iw_dir = iw_dir / nla.norm( iw_dir ) if self.cached_christoffel is not None: christoffel = self.cached_christoffel else: coefs = self.eval_homogenized_coefs() christoffel = compute_cat( coefs, iw_dir, self.app_options.dispersion ) report_iw_cat( iw_dir, christoffel ) self.cached_christoffel = christoffel if ret_iw_dir: return christoffel, iw_dir else: return christoffel
def prepare_cylindrical_transform(coors, origin, mode='axes'): """ Prepare matrices for transforming tensors into cylindrical coordinates with the axis 'z' in a given origin. Parameters ---------- coors : array The Cartesian coordinates. origin : array of length 3 The origin. mode : 'axes' or 'data' In 'axes' (default) mode the matrix transforms data to different coordinate system, while in 'data' mode the matrix transforms the data in the same coordinate system and is transpose of the matrix in the 'axes' mode. Returns ------- mtx : array The array of transformation matrices for each coordinate in `coors`. """ assert_(mode in ['axes', 'data']) x, y = coors[:,0] - origin[0], coors[:,1] - origin[1] theta = nm.arctan2(y, x) if mode == 'data': theta = -theta mtx = nm.zeros((coors.shape[0], 3, 3), dtype=nm.float64) for ii, th in enumerate(theta): mtx[ii] = make_axis_rotation_matrix([0.0, 0.0, 1.0], th) return mtx
def parse_view(option, opt, value, parser): vals = value.split(',') assert_(len(vals) in [2, 3, 6]) val = tuple(float(ii) for ii in vals) if len(vals) == 6: val = val[:3] + (list(val[3:]),) setattr(parser.values, option.dest, val)
def norm_l2_along_axis(ar, axis=1, n_item=None, squared=False): """Compute l2 norm of rows (axis=1) or columns (axis=0) of a 2D array. n_item ... use only the first n_item columns/rows squared ... if True, return the norm squared """ assert_(axis in [0, 1]) assert_(ar.ndim == 2) other = 1 - axis vec = nm.zeros((ar.shape[other],), dtype=nm.float64) if n_item is None: n_item = ar.shape[axis] else: n_item = min( n_item, ar.shape[axis] ) if axis == 1: for ii in range( n_item ): vec += ar[:,ii]**2 else: for ii in range( n_item ): vec += ar[ii,:]**2 if not squared: vec = nm.sqrt( vec ) return vec
def plot_displacements( source, ctp, bbox, position, family, kind, name, rel_scaling=1.0, color_kind=None, color_name=None, opacity=1.0 ): """ Show displacements by displaying a colormap given by quantity `color_name` on the deformed mesh. Parameters ---------- rel_scaling : float The relative scaling of displacements. color_kind : str, optional The kind of data determining the colormap. color_name : str, optional The name of data determining the colormap. opacity : float The surface plot opacity. """ assert_(kind == "vectors") if color_name is None: active = mlab.pipeline.set_active_attribute(source) else: active = mlab.pipeline.set_active_attribute(ctp) active.point_vectors_name = name active = mlab.pipeline.warp_vector(active) active.filter.scale_factor = rel_scaling if color_name is None: new_kind = kind new_name = name active = mlab.pipeline.extract_vector_norm(active) else: new_kind = "scalars" if color_kind == "tensors": new_name = "|%s|" % color_name active = mlab.pipeline.set_active_attribute(active) active.point_tensors_name = color_name active = mlab.pipeline.extract_tensor_components(active) elif color_kind == "vectors": new_name = "|%s|" % color_name active = mlab.pipeline.set_active_attribute(active) active.point_vectors_name = color_name active = mlab.pipeline.extract_tensor_components(active) elif color_kind == "scalars": new_name = "%s" % color_name active = mlab.pipeline.set_active_attribute(active) active.point_scalars_name = color_name surf = mlab.pipeline.surface(active, opacity=opacity) surf.actor.actor.position = position return new_kind, new_name, active
def get_edge_graph(self): """ Return the graph of region edges as a sparse matrix having uid(k) + 1 at (i, j) if vertex[i] is connected with vertex[j] by the edge k. Degenerate edges are ignored. """ from scipy.sparse import csr_matrix cmesh = self.domain.cmesh e_verts = cmesh.get_incident(0, self.edges, 1) e_verts.shape = (e_verts.shape[0] / 2, 2) ii = nm.where(e_verts[:, 0] != e_verts[:, 1])[0] edges = self.edges[ii] e_verts = e_verts[ii] vals = edges + 1 rows = e_verts[:, 0] cols = e_verts[:, 1] num = self.vertices.max() + 1 graph = csr_matrix((vals, (rows, cols)), shape=(num, num)) nnz = graph.nnz # Symmetrize. graph = graph + graph.T assert_(graph.nnz == 2 * nnz) return graph
def solve_pressure_eigenproblem(self, mtx, eig_problem=None, n_eigs=0, check=False): """G = B*AI*BT or B*AI*BT+D""" def get_slice(n_eigs, nn): if n_eigs > 0: ii = slice(0, n_eigs) elif n_eigs < 0: ii = slice(nn + n_eigs, nn) else: ii = slice(0, 0) return ii eig_problem = get_default(eig_problem, self.eig_problem) n_eigs = get_default(n_eigs, self.n_eigs) check = get_default(check, self.check) mtx_c, mtx_b, action_aibt = mtx['C'], mtx['B'], mtx['action_aibt'] mtx_g = mtx_b * action_aibt.to_array() # mtx_b must be sparse! if eig_problem == 'B*AI*BT+D': mtx_g += mtx['D'].toarray() mtx['G'] = mtx_g output(mtx_c.shape, mtx_g.shape) eigs, mtx_q = eig(mtx_c.toarray(), mtx_g, method='eig.sgscipy') if check: ee = nm.diag(sc.dot(mtx_q.T * mtx_c, mtx_q)).squeeze() oo = nm.diag(sc.dot(sc.dot(mtx_q.T, mtx_g), mtx_q)).squeeze() try: assert_(nm.allclose(ee, eigs)) assert_(nm.allclose(oo, nm.ones_like(eigs))) except ValueError: debug() nn = mtx_c.shape[0] if isinstance(n_eigs, tuple): output('required number of eigenvalues: (%d, %d)' % n_eigs) if sum(n_eigs) < nn: ii0 = get_slice(n_eigs[0], nn) ii1 = get_slice(-n_eigs[1], nn) eigs = nm.concatenate((eigs[ii0], eigs[ii1])) mtx_q = nm.concatenate((mtx_q[:,ii0], mtx_q[:,ii1]), 1) else: output('required number of eigenvalues: %d' % n_eigs) if (n_eigs != 0) and (abs(n_eigs) < nn): ii = get_slice(n_eigs, nn) eigs = eigs[ii] mtx_q = mtx_q[:,ii] ## from sfepy.base.plotutils import pylab, iplot ## pylab.semilogy(eigs) ## pylab.figure(2) ## iplot(eigs) ## pylab.show() ## debug() out = Struct(eigs=eigs, mtx_q=mtx_q) return out
def barycentric_coors(coors, s_coors): """ Get barycentric (area in 2D, volume in 3D) coordinates of points with coordinates `coors` w.r.t. the simplex given by `s_coors`. Returns ------- bc : array The barycentric coordinates. Then reference element coordinates `xi = dot(bc.T, ref_coors)`. """ n_v, dim = s_coors.shape n_c, dim2 = coors.shape assert_(dim == dim2) assert_(n_v == (dim + 1)) mtx = nm.ones((n_v, n_v), nm.float64) mtx[0:n_v-1,:] = s_coors.T rhs = nm.empty((n_v,n_c), nm.float64) rhs[0:n_v-1,:] = coors.T rhs[n_v-1,:] = 1.0 bc = nla.solve(mtx, rhs) return bc
def __call__(self, problem=None, data=None): problem = get_default(problem, self.problem) problem.set_equations(self.equations) problem.select_bcs(ebc_names=self.ebcs, epbc_names=self.epbcs, lcbc_names=self.get_default_attr('lcbcs', [])) problem.update_materials(problem.ts) self.init_solvers(problem) variables = problem.get_variables() states = nm.zeros((self.dim,), dtype=nm.object) clist = [] for ir in range(self.dim): if isinstance(self.set_variables, list): self.set_variables_default(variables, ir, self.set_variables, data) else: self.set_variables(variables, ir, **data) state = problem.solve() assert_(state.has_ebc()) states[ir] = state.get_parts() clist.append((ir,)) corr_sol = CorrSolution(name=self.name, states=states, components=clist) self.save(corr_sol, problem) return corr_sol
def get_cell_indices(self, cells, true_cells_only=True): """ Return indices of `cells` in the region cells. Raises ValueError if `true_cells_only` is True and the region kind does not allow cells. For `true_cells_only` equal to False, cells incident to facets are returned if the region itself contains no cells. Notes ----- If the number of unique values in `cells` is smaller or equal to the number of cells in the region, all `cells` has to be also the region cells (`self` is a superset of `cells`). The region cells are considered depending on `true_cells_only`. Otherwise, indices of all cells in `self` that are in `cells` are returned. """ fcells = self.get_cells(true_cells_only=true_cells_only) if len(nm.unique(cells)) <= len(nm.unique(fcells)): # self is a superset of cells. ii = nm.searchsorted(fcells, cells) assert_((fcells[ii] == cells).all()) else: aux = nm.searchsorted(cells, fcells) ii = nm.where(nm.take(cells, aux, mode='clip') == fcells)[0] return ii
def _setup_vertex_dofs(self): """ Setup vertex DOF connectivity. """ if self.node_desc.vertex is None: return 0, None region = self.region cmesh = self.domain.cmesh conn, offsets = cmesh.get_incident(0, region.cells, region.tdim, ret_offsets=True) vertices = nm.unique(conn) remap = prepare_remap(vertices, region.n_v_max) n_dof = vertices.shape[0] aux = nm.unique(nm.diff(offsets)) assert_(len(aux) == 1, 'region with multiple reference geometries!') offset = aux[0] # Remap vertex node connectivity to field-local numbering. aux = conn.reshape((-1, offset)).astype(nm.int32) self.econn[:, :offset] = nm.take(remap, aux) return n_dof, remap
def set_dofs(self, fun=0.0, region=None, dpn=None, warn=None): """ Set the values of DOFs in a given region using a function of space coordinates or value `fun`. """ if region is None: region = self.region if dpn is None: dpn = self.shape[0] aux = self.get_dofs_in_region(region, clean=True, warn=warn) nods = nm.unique(nm.hstack(aux)) if callable(fun): vals = fun(self.get_coor(nods)) elif nm.isscalar(fun): vals = nm.repeat([fun], nods.shape[0] * dpn) elif isinstance(fun, nm.ndarray): assert_(len(fun) == dpn) vals = nm.repeat(fun, nods.shape[0]) else: raise ValueError('unknown function/value type! (%s)' % type(fun)) return nods, vals
def __init__(self, name, regions, dof_names, dof_map_fun, filename, variables, ts=None, functions=None): MRLCBCOperator.__init__(self, name, regions, dof_names, dof_map_fun, variables, functions=functions) self.filename = filename dim = self.region.dim assert_(len(self.dof_names) == dim) can_save = ((self.filename is not None) and ((ts is None) or ((ts is not None) and ts.step == 0))) filename = self.filename if can_save else None vectors = self.get_vectors(self.mdofs, self.region, self.field, filename=filename) n_nod, dim = vectors.shape data = vectors.ravel() rows = nm.arange(data.shape[0]) cols = nm.repeat(nm.arange(n_nod), dim) mtx = sp.coo_matrix((data, (rows, cols)), shape=(n_nod * dim, n_nod)) self.n_mdof = n_nod * dim self.n_new_dof = n_nod self.mtx = mtx.tocsr()
def __call__( self, problem = None, data = None, save_hook = None ): """data: corrs_pressure, evp, optionally vec_g""" problem = get_default( problem, self.problem ) ts = problem.get_time_solver().ts corrs, evp = [data[ii] for ii in self.requires[:2]] if len(self.requires) == 3: vec_g = data[self.requires[2]] else: vec_g = None assert_( evp.ebcs == self.ebcs ) assert_( evp.epbcs == self.epbcs ) filename = self.get_dump_name() savename = self.get_save_name() self.setup_equations(self.equations) solve = self.compute_correctors solve(evp, 1.0, corrs.state, ts, filename, savename, vec_g=vec_g) if self.check: self.setup_equations(self.verify_equations) self.init_solvers(problem) output( 'verifying correctors %s...' % self.name ) verify = self.verify_correctors ok = verify(1.0, corrs.state, filename) output( '...done, ok: %s' % ok ) return Struct( name = self.name, filename = filename )
def __call__(self, problem=None, data=None): problem = get_default(problem, self.problem) problem.set_equations(self.equations) problem.select_bcs(ebc_names=self.ebcs, epbc_names=self.epbcs, lcbc_names=self.get_default_attr('lcbcs', [])) problem.update_materials(problem.ts) self.init_solvers(problem) variables = problem.get_variables() if hasattr(self, 'set_variables'): if isinstance(self.set_variables, list): self.set_variables_default(variables, self.set_variables, data) else: self.set_variables(variables, **data) state = problem.solve() assert_(state.has_ebc()) corr_sol = CorrSolution(name=self.name, state=state.get_parts()) self.save(corr_sol, problem) return corr_sol
def __call__(self, volume=None, problem=None, data=None): problem = get_default(problem, self.problem) opts = self.app_options iw_dir = nm.array(opts.incident_wave_dir, dtype=nm.float64) dim = problem.get_dim() assert_(dim == iw_dir.shape[0]) iw_dir = iw_dir / nla.norm(iw_dir) dispersion = data[self.requires[0]] wave_vectors = dispersion.logs.eig_vectors pas = [] iw_dir = iw_dir / nla.norm(iw_dir) idims = range(iw_dir.shape[0]) pi2 = 0.5 * nm.pi for vecs in wave_vectors: pa = nm.empty(vecs.shape[:-1], dtype=nm.float64) for ir, vec in enumerate(vecs): for ic in idims: vv = vec[:,ic] # Ensure the angle is in [0, pi/2]. val = nm.arccos(nm.dot(iw_dir, vv) / nla.norm(vv)) if val > pi2: val = nm.pi - val pa[ir,ic] = val pas.append(pa) return pas
def create_mapping(coors, gel, order): """ Create mapping from transformed (in `x-y` plane) element faces to reference element faces. Parameters ---------- coors : array The transformed coordinates of element nodes, shape `(n_el, n_ep, dim)`. The function verifies that the all `z` components are zero. gel : GeometryElement instance The geometry element corresponding to the faces. order : int The polynomial order of the mapping. Returns ------- mapping : VolumeMapping instance The reference element face mapping. """ # Strip 'z' component (should be 0 now...). assert_(nm.allclose(coors[:, :, -1], 0.0, rtol=1e-12, atol=1e-12)) coors = coors[:, :, :-1].copy() # Mapping from transformed element to reference element. sh = coors.shape seq_coors = coors.reshape((sh[0] * sh[1], sh[2])) seq_conn = nm.arange(seq_coors.shape[0], dtype=nm.int32) seq_conn.shape = sh[:2] mapping = VolumeMapping(seq_coors, seq_conn, gel=gel, order=1) return mapping
def get_edge_graph(self): """ Return the graph of region edges as a sparse matrix having uid(k) + 1 at (i, j) if vertex[i] is connected with vertex[j] by the edge k. Degenerate edges are ignored. """ from scipy.sparse import csr_matrix ed = self.domain.ed rows, cols, vals = [], [], [] for ig, edges in self.edges.iteritems(): e_verts = ed.facets[edges] ii = nm.where(e_verts[:, 0] != e_verts[:, 1])[0] edges = edges[ii] e_verts = e_verts[ii] vals.append(ed.uid_i[edges] + 1) rows.append(e_verts[:, 0]) cols.append(e_verts[:, 1]) vals, indx = nm.unique(nm.concatenate(vals), return_index=True) rows = nm.concatenate(rows)[indx] cols = nm.concatenate(cols)[indx] num = self.all_vertices.max() + 1 graph = csr_matrix((vals, (rows, cols)), shape=(num, num)) nnz = graph.nnz # Symmetrize. graph = graph + graph.T assert_(graph.nnz == 2 * nnz) return graph
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 assemble_to(self, asm_obj, val, iels, mode='vector', diff_var=None): """ Assemble the results of term evaluation. For standard terms, assemble the values in `val` corresponding to elements/cells `iels` into a vector or a CSR sparse matrix `asm_obj`, depending on `mode`. For terms with a dynamic connectivity (e.g. contact terms), in `'matrix'` mode, return the extra COO sparse matrix instead. The extra matrix has to be added to the global matrix by the caller. By default, this is done in :func:`Equations.evaluate() <sfepy.discrete.equations.Equations.evaluate()>`. """ import sfepy.discrete.common.extmods.assemble as asm vvar = self.get_virtual_variable() dc_type = self.get_dof_conn_type() extra = None if mode == 'vector': if asm_obj.dtype == nm.float64: assemble = asm.assemble_vector else: assert_(asm_obj.dtype == nm.complex128) assemble = asm.assemble_vector_complex for ii in range(len(val)): if not (val[ii].dtype == nm.complex128): val[ii] = nm.complex128(val[ii]) if not isinstance(val, tuple): dc = vvar.get_dof_conn(dc_type) assert_(val.shape[2] == dc.shape[1]) assemble(asm_obj, val, iels, 1.0, dc) else: vals, rows, var = val if var.eq_map is not None: eq = var.eq_map.eq rows = eq[rows] active = (rows >= 0) vals, rows = vals[active], rows[active] # Assumes no repeated indices in rows! asm_obj[rows] += vals elif mode == 'matrix': if asm_obj.dtype == nm.float64: assemble = asm.assemble_matrix else: assert_(asm_obj.dtype == nm.complex128) assemble = asm.assemble_matrix_complex svar = diff_var tmd = (asm_obj.data, asm_obj.indptr, asm_obj.indices) if ((asm_obj.dtype == nm.complex128) and (val.dtype == nm.float64)): val = val.astype(nm.complex128) sign = 1.0 if self.arg_derivatives[svar.name]: if not self.is_quasistatic or (self.step > 0): sign *= 1.0 / self.dt else: sign = 0.0 if not isinstance(val, tuple): rdc = vvar.get_dof_conn(dc_type) is_trace = self.arg_traces[svar.name] trace_region = self.arg_trace_regions[svar.name] cdc = svar.get_dof_conn(dc_type, is_trace, trace_region) assert_(val.shape[2:] == (rdc.shape[1], cdc.shape[1])) assemble(tmd[0], tmd[1], tmd[2], val, iels, sign, rdc, cdc) else: from scipy.sparse import coo_matrix vals, rows, cols, rvar, cvar = val if rvar.eq_map is not None: req, ceq = rvar.eq_map.eq, cvar.eq_map.eq rows, cols = req[rows], ceq[cols] active = (rows >= 0) & (cols >= 0) vals, rows, cols = vals[active], rows[active], cols[active] extra = coo_matrix((sign * vals, (rows, cols)), shape=asm_obj.shape) else: raise ValueError('unknown assembling mode! (%s)' % mode) return extra
def evaluate(self, mode='eval', diff_var=None, standalone=True, ret_status=False, **kwargs): """ Evaluate the term. Parameters ---------- mode : 'eval' (default), or 'weak' The term evaluation mode. Returns ------- val : float or array In 'eval' mode, the term returns a single value (the integral, it does not need to be a scalar), while in 'weak' mode it returns an array for each element. status : int, optional The flag indicating evaluation success (0) or failure (nonzero). Only provided if `ret_status` is True. iels : array of ints, optional The local elements indices in 'weak' mode. Only provided in non-'eval' modes. """ if standalone: self.standalone_setup() kwargs = kwargs.copy() term_mode = kwargs.pop('term_mode', None) if mode in ('eval', 'el_eval', 'el_avg', 'qp'): args = self.get_args(**kwargs) self.check_shapes(*args) emode = 'eval' if mode == 'el_eval' else mode _args = tuple(args) + (emode, term_mode, diff_var) shape, dtype = self.get_eval_shape(*_args, **kwargs) if shape[0] == 0: val = nm.zeros(shape, dtype=dtype) status = 0 else: fargs = self.call_get_fargs(_args, kwargs) if dtype == nm.float64: val, status = self.eval_real(shape, fargs, mode, term_mode, **kwargs) elif dtype == nm.complex128: val, status = self.eval_complex(shape, fargs, mode, term_mode, **kwargs) else: raise ValueError('unsupported term dtype! (%s)' % dtype) val *= self.sign out = (val, ) elif mode == 'weak': varr = self.get_virtual_variable() if varr is None: raise ValueError( 'no virtual variable in weak mode! (in "%s")' % self.get_str()) if diff_var is not None: varc = self.get_variables(as_list=False)[diff_var] args = self.get_args(**kwargs) self.check_shapes(*args) n_elr, n_qpr, dim, n_enr, n_cr = self.get_data_shape(varr) n_row = n_cr * n_enr if diff_var is None: shape = (n_elr, 1, n_row, 1) else: n_elc, n_qpc, dim, n_enc, n_cc = self.get_data_shape(varc) n_col = n_cc * n_enc shape = (n_elr, 1, n_row, n_col) if shape[0] == 0: vals = nm.zeros(shape, dtype=varr.dtype) status = 0 else: _args = tuple(args) + (mode, term_mode, diff_var) fargs = self.call_get_fargs(_args, kwargs) if varr.dtype == nm.float64: vals, status = self.eval_real(shape, fargs, mode, term_mode, diff_var, **kwargs) elif varr.dtype == nm.complex128: vals, status = self.eval_complex(shape, fargs, mode, term_mode, diff_var, **kwargs) else: raise ValueError('unsupported term dtype! (%s)' % varr.dtype) if not isinstance(vals, tuple): vals *= self.sign iels = self.get_assembling_cells(vals.shape) else: vals = (self.sign * vals[0], ) + vals[1:] iels = None out = (vals, iels) if goptions['check_term_finiteness']: assert_(nm.isfinite(out[0]).all(), msg='"%s" term values not finite!' % self.get_str()) if ret_status: out = out + (status, ) if len(out) == 1: out = out[0] return out
def _define_nodes(self): geometry = self.geometry order = self.order n_v, dim = geometry.n_vertex, geometry.dim n_nod, n_per_edge, n_per_face, n_bubble = self._get_counts() nodes = nm.zeros((n_nod, dim), nm.int32) nts = nm.zeros((n_nod, 2), nm.int32) # Vertex nodes. nts[0:n_v, 0] = 0 nts[0:n_v, 1] = nm.arange(n_v, dtype=nm.int32) nodes[0:n_v] = nm.array(vertex_maps[dim], dtype=nm.int32) ii = n_v # Edge nodes. if (dim > 1) and (n_per_edge > 0): ik = nm.arange(2, order + 1, dtype=nm.int32) zo = nm.zeros((n_per_edge, 2), dtype=nm.int32) zo[:, 1] = 1 for ie, edge in enumerate(geometry.edges): n1, n2 = nodes[edge] ifix = nm.where(n1 == n2)[0] irun = nm.where(n1 != n2)[0][0] ic = n1[ifix] nodes[ii:ii + n_per_edge, ifix] = zo[:, ic] nodes[ii:ii + n_per_edge, irun] = ik nts[ii:ii + n_per_edge] = [[1, ie]] ii += n_per_edge # 3D face nodes. face_axes = [] sfnodes = None if (dim == 3) and (n_per_face > 0): n_face = len(geometry.faces) sfnodes = nm.zeros((n_per_face * n_face, dim), nm.int32) ii0 = ii ik = nm.arange(2, order + 1, dtype=nm.int32) zo = nm.zeros((n_per_face, 2), dtype=nm.int32) zo[:, 1] = 1 for ifa, face in enumerate(geometry.faces): ns = nodes[face] diff = nm.diff(ns, axis=0) asum = nm.abs(diff).sum(axis=0) ifix = nm.where(asum == 0)[0][0] ic = ns[0, ifix] irun1 = nm.where(asum == 2)[0][0] irun2 = nm.where(asum == 1)[0][0] iy, ix = nm.meshgrid(ik, ik) nodes[ii:ii + n_per_face, ifix] = zo[:, ic] nodes[ii:ii + n_per_face, irun1] = ix.ravel() nodes[ii:ii + n_per_face, irun2] = iy.ravel() nts[ii:ii + n_per_face] = [[2, ifa]] ij = ii - ii0 sfnodes[ij:ij + n_per_face, ifix] = zo[:, ic] sfnodes[ij:ij + n_per_face, irun1] = iy.ravel() sfnodes[ij:ij + n_per_face, irun2] = ix.ravel() face_axes.append([irun1, irun2]) ii += n_per_face face_axes = nm.array(face_axes) # Bubble nodes. if n_bubble > 0: ik = nm.arange(2, order + 1, dtype=nm.int32) nodes[ii:] = nm.array([aux for aux in combine([ik] * dim)]) nts[ii:ii + n_bubble] = [[3, 0]] ii += n_bubble assert_(ii == n_nod) # Coordinates of the "nodes". All nodes on a facet have the same # coordinates - the centre of the facet. c_min, c_max = self.bbox[:, 0] node_coors = nm.zeros(nodes.shape, dtype=nm.float64) node_coors[:n_v] = nodes[:n_v] if (dim > 1) and (n_per_edge > 0): ie = nm.where(nts[:, 0] == 1)[0] node_coors[ie] = node_coors[geometry.edges[nts[ie, 1]]].mean(1) if (dim == 3) and (n_per_face > 0): ifa = nm.where(nts[:, 0] == 2)[0] node_coors[ifa] = node_coors[geometry.faces[nts[ifa, 1]]].mean(1) if n_bubble > 0: ib = nm.where(nts[:, 0] == 3)[0] node_coors[ib] = node_coors[geometry.conn].mean(0) return nodes, nts, node_coors, face_axes, sfnodes
def describe_geometry(self, field, gtype, region, integral=None, return_mapping=False): """ Compute jacobians, element volumes and base function derivatives for Volume-type geometries (volume mappings), and jacobians, normals and base function derivatives for Surface-type geometries (surface mappings). Notes ----- - volume mappings can be defined on a part of an element group, although the field has to be defined always on the whole group. - surface mappings are defined on the surface region - surface mappings require field order to be > 0 """ domain = field.domain group = domain.groups[self.ig] coors = domain.get_mesh_coors(actual=True) if gtype == 'volume': if integral is None: from sfepy.fem import Integral integral = Integral('i_tmp', 'v', 1) qp = self.get_qp('v', integral) iels = region.cells[self.ig] geo_ps = self.interp.get_geom_poly_space('v') ps = self.interp.poly_spaces['v'] bf = self.get_base('v', 0, integral, iels=iels) conn = nm.take(group.conn, iels, axis=0) mapping = VolumeMapping(coors, conn, poly_space=geo_ps) vg = mapping.get_mapping(qp.vals, qp.weights, poly_space=ps, ori=self.ori) out = vg elif (gtype == 'surface') or (gtype == 'surface_extra'): assert_(field.approx_order > 0) if self.ori is not None: msg = 'surface integrals do not work yet with the' \ ' hierarchical basis!' raise ValueError(msg) sd = domain.surface_groups[self.ig][region.name] esd = self.surface_data[region.name] qp = self.get_qp(sd.face_type, integral) geo_ps = self.interp.get_geom_poly_space(sd.face_type) ps = self.interp.poly_spaces[esd.face_type] bf = self.get_base(esd.face_type, 0, integral) conn = sd.get_connectivity() mapping = SurfaceMapping(coors, conn, poly_space=geo_ps) sg = mapping.get_mapping(qp.vals, qp.weights, poly_space=ps) if gtype == 'surface_extra': sg.alloc_extra_data(self.get_v_data_shape()[2]) self.create_bqp(region.name, integral) qp = self.qp_coors[(integral.name, esd.bkey)] v_geo_ps = self.interp.get_geom_poly_space('v') bf_bg = v_geo_ps.eval_base(qp.vals, diff=True) ebf_bg = self.get_base(esd.bkey, 1, integral) sg.evaluate_bfbgm(bf_bg, ebf_bg, coors, sd.fis, group.conn) out = sg elif gtype == 'point': out = mapping = None else: raise ValueError('unknown geometry type: %s' % gtype) if out is not None: # Store the integral used. out.integral = integral out.qp = qp out.ps = ps # Update base. out.bf[:] = bf if return_mapping: out = (out, mapping) return out
def get_geom_poly_space(self, key): assert_(key[0] == 's') ps = self.gel.interp.poly_spaces['v'] return ps
def create_task_dof_maps(field, cell_tasks, inter_facets, is_overlap=True, use_expand_dofs=False, save_inter_regions=False, output_dir=None): """ For each task list its inner and interface DOFs of the given field and create PETSc numbering that is consecutive in each subdomain. For each task, the DOF map has the following structure:: [inner, [own_inter1, own_inter2, ...], [overlap_cells1, overlap_cells2, ...], n_task_total, task_offset] The overlapping cells are defined so that the system matrix corresponding to each task can be assembled independently, see [1]. TODO: Some "corner" cells may be added even if not needed - filter them out by using the PETSc DOFs range. When debugging domain partitioning problems, it is advisable to set `save_inter_regions` to True to save the task interfaces as meshes as well as vertex-based markers - to be used only with moderate problems and small numbers of tasks. [1] J. Sistek and F. Cirak. Parallel iterative solution of the incompressible Navier-Stokes equations with application to rotating wings. Submitted for publication, 2015 """ domain = field.domain cmesh = domain.cmesh if use_expand_dofs: id_map = nm.zeros(field.n_nod * field.n_components, dtype=nm.uint32) else: id_map = nm.zeros(field.n_nod, dtype=nm.uint32) def _get_dofs_region(field, region): dofs = field.get_dofs_in_region(region) if use_expand_dofs: dofs = expand_dofs(dofs, field.n_components) return dofs def _get_dofs_conn(field, conn): dofs = nm.unique(conn) if use_expand_dofs: dofs = expand_dofs(dofs, field.n_components) return dofs dof_maps = {} count = 0 inter_count = 0 ocs = nm.zeros(0, dtype=nm.int32) cell_parts = [] for ir, ntasks in ordered_iteritems(inter_facets): cells = nm.where(cell_tasks == ir)[0].astype(nm.int32) cell_parts.append(cells) cregion = Region.from_cells(cells, domain, name='task_%d' % ir) domain.regions.append(cregion) dofs = _get_dofs_region(field, cregion) rdof_map = dof_maps.setdefault(ir, [None, [], [], 0, 0]) inter_dofs = [] for ic, facets in ordered_iteritems(ntasks): cdof_map = dof_maps.setdefault(ic, [None, [], [], 0, 0]) name = 'inter_%d_%d' % (ir, ic) ii = ir region = Region.from_facets(facets, domain, name, parent=cregion.name) region.update_shape() if save_inter_regions: output_dir = output_dir if output_dir is not None else '.' filename = os.path.join(output_dir, '%s.mesh' % name) aux = domain.mesh.from_region(region, domain.mesh, is_surface=True) aux.write(filename, io='auto') mask = nm.zeros((domain.mesh.n_nod, 1), dtype=nm.float64) mask[region.vertices] = 1 out = {name: Struct(name=name, mode='vertex', data=mask)} filename = os.path.join(output_dir, '%s.h5' % name) domain.mesh.write(filename, out=out, io='auto') inter_dofs.append(_get_dofs_region(field, region)) sd = FESurface('surface_data_%s' % region.name, region, field.efaces, field.econn, field.region) econn = sd.get_connectivity() n_facet = econn.shape[0] ii2 = max(int(n_facet / 2), 1) dr = _get_dofs_conn(field, econn[:ii2]) ii = nm.where((id_map[dr] == 0))[0] n_new = len(ii) if n_new: rdof_map[1].append(dr[ii]) rdof_map[3] += n_new id_map[dr[ii]] = 1 inter_count += n_new count += n_new if is_overlap: ovs = cmesh.get_incident(0, region.facets[:ii2], cmesh.tdim - 1) ocs = cmesh.get_incident(cmesh.tdim, ovs, 0) rdof_map[2].append(ocs.astype(nm.int32)) dc = _get_dofs_conn(field, econn[ii2:]) ii = nm.where((id_map[dc] == 0))[0] n_new = len(ii) if n_new: cdof_map[1].append(dc[ii]) cdof_map[3] += n_new id_map[dc[ii]] = 1 inter_count += n_new count += n_new if is_overlap: ovs = cmesh.get_incident(0, region.facets[ii2:], cmesh.tdim - 1) ocs = cmesh.get_incident(cmesh.tdim, ovs, 0) cdof_map[2].append(ocs.astype(nm.int32)) domain.regions.pop() # Remove the cell region. inner_dofs = nm.setdiff1d(dofs, nm.concatenate(inter_dofs)) n_inner = len(inner_dofs) rdof_map[3] += n_inner assert_(nm.all(id_map[inner_dofs] == 0)) id_map[inner_dofs] = 1 count += n_inner rdof_map[0] = inner_dofs offset = 0 overlap_cells = [] for ir, dof_map in ordered_iteritems(dof_maps): n_owned = dof_map[3] i0 = len(dof_map[0]) id_map[dof_map[0]] = nm.arange(offset, offset + i0, dtype=nm.uint32) for aux in dof_map[1]: i1 = len(aux) id_map[aux] = nm.arange(offset + i0, offset + i0 + i1, dtype=nm.uint32) i0 += i1 if len(dof_map[2]): ocs = nm.unique(nm.concatenate(dof_map[2])) else: ocs = nm.zeros(0, dtype=nm.int32) overlap_cells.append(ocs) assert_(i0 == n_owned) dof_map[4] = offset offset += n_owned if not len(dof_maps): dofs = _get_dofs_region(field, field.region) dof_maps[0] = [dofs, [], [], len(dofs), 0] id_map[:] = nm.arange(len(dofs), dtype=nm.uint32) if not len(cell_parts): cell_parts.append(nm.arange(len(cell_tasks), dtype=nm.int32)) if not len(overlap_cells): overlap_cells.append(nm.zeros(0, dtype=nm.int32)) return dof_maps, id_map, cell_parts, overlap_cells
def test_sparse_matrix_hdf5( self ): from sfepy.base.ioutils import write_sparse_matrix_hdf5, read_sparse_matrix_hdf5 from sfepy.base.ioutils import pt if pt is None: self.report( 'skipped (no pytables)' ) return True filename = op.join( self.options.out_dir, 'mtx.h5' ) aux = nm.random.rand( 5, 5 ) aux[1,:] = aux[:,2] = aux[3,:] = 0.0 mtx = sp.csr_matrix( aux, dtype = nm.float64 ) # self.report( 'sparse matrix:\n%s' % mtx ) self.report( 'saving matrix into %s...' % filename ) write_sparse_matrix_hdf5( filename, mtx ) self.report( 'reading...' ) mtx2 = read_sparse_matrix_hdf5( filename ) # self.report( 'read matrix:\n%s' % mtx2 ) self.report( 'difference:\n%s' % (mtx2 - mtx).__repr__() ) assert_( mtx.shape == mtx2.shape ) assert_( mtx.dtype == mtx2.dtype ) assert_( mtx.format == mtx2.format ) assert_( nm.allclose( mtx.data, mtx2.data ) ) assert_( nm.allclose( mtx.indices, mtx2.indices ) ) assert_( nm.allclose( mtx.indptr, mtx2.indptr ) ) return True
def linearize(self, dofs, min_level=0, max_level=1, eps=1e-4): """ Linearize the solution for post-processing. Parameters ---------- dofs : array, shape (n_nod, n_component) The array of DOFs reshaped so that each column corresponds to one component. min_level : int The minimum required level of mesh refinement. max_level : int The maximum level of mesh refinement. eps : float The relative tolerance parameter of mesh adaptivity. Returns ------- mesh : Mesh instance The adapted, nonconforming, mesh. vdofs : array The DOFs defined in vertices of `mesh`. levels : array of ints The refinement level used for each element group. """ assert_(dofs.ndim == 2) n_nod, dpn = dofs.shape assert_(n_nod == self.n_nod) assert_(dpn == self.shape[0]) vertex_coors = self.coors[:self.n_vertex_dof, :] coors = [] vdofs = [] conns = [] mat_ids = [] levels = [] offset = 0 for ig, ap in self.aps.iteritems(): ps = ap.interp.poly_spaces['v'] gps = ap.interp.gel.interp.poly_spaces['v'] group = self.domain.groups[ig] vertex_conn = ap.econn[:, :group.shape.n_ep] eval_dofs = get_eval_dofs(dofs, ap.econn, ps, ori=ap.ori) eval_coors = get_eval_coors(vertex_coors, vertex_conn, gps) (level, _coors, conn, _vdofs, _mat_ids) = create_output(eval_dofs, eval_coors, group.shape.n_el, ps, min_level=min_level, max_level=max_level, eps=eps) _mat_ids[:] = self.domain.mesh.mat_ids[ig][0] coors.append(_coors) vdofs.append(_vdofs) conns.append(conn + offset) mat_ids.append(_mat_ids) levels.append(level) offset += _coors.shape[0] coors = nm.concatenate(coors, axis=0) vdofs = nm.concatenate(vdofs, axis=0) mesh = Mesh.from_data('linearized_mesh', coors, None, conns, mat_ids, self.domain.mesh.descs) return mesh, vdofs, levels
def _gen_common_data(orders, gels, report): import sfepy from sfepy.base.base import Struct from sfepy.linalg import combine from sfepy.fem import Mesh, Domain, Field, FieldVariable, Integral from sfepy.fem.global_interp import get_ref_coors bases = ([ii for ii in combine([['2_4', '3_8'], ['lagrange', 'lobatto']])] + [ii for ii in combine([['2_3', '3_4'], ['lagrange']])]) for geom, poly_space_base in bases: report('geometry: %s, base: %s' % (geom, poly_space_base)) order = orders[geom] integral = Integral('i', order=order) aux = '' if geom in ['2_4', '3_8'] else 'z' mesh0 = Mesh.from_file('meshes/elements/%s_2%s.mesh' % (geom, aux), prefix_dir=sfepy.data_dir) gel = gels[geom] perms = gel.get_conn_permutations() qps, qp_weights = integral.get_qp(gel.surface_facet.name) zz = nm.zeros_like(qps[:, :1]) qps = nm.hstack(([qps] + [zz])) shift = shifts[geom] rcoors = nm.ascontiguousarray(qps + shift[:1, :] - shift[1:, :]) ccoors = nm.ascontiguousarray(qps + shift[:1, :] + shift[1:, :]) for ir, pr in enumerate(perms): for ic, pc in enumerate(perms): report('ir: %d, ic: %d' % (ir, ic)) report('pr: %s, pc: %s' % (pr, pc)) mesh = mesh0.copy() conn = mesh.conns[0] conn[0, :] = conn[0, pr] conn[1, :] = conn[1, pc] cache = Struct(mesh=mesh) domain = Domain('domain', mesh) omega = domain.create_region('Omega', 'all') region = domain.create_region('Facet', rsels[geom], 'facet') field = Field.from_args('f', nm.float64, shape=1, region=omega, approx_order=order, poly_space_base=poly_space_base) var = FieldVariable('u', 'unknown', field, 1) report('# dofs: %d' % var.n_dof) vec = nm.empty(var.n_dof, dtype=var.dtype) ap = field.aps[0] ps = ap.interp.poly_spaces['v'] dofs = field.get_dofs_in_region_group(region, 0, merge=False) edofs, fdofs = nm.unique(dofs[1]), nm.unique(dofs[2]) rrc, rcells, rstatus = get_ref_coors(field, rcoors, cache=cache) crc, ccells, cstatus = get_ref_coors(field, ccoors, cache=cache) assert_((rstatus == 0).all() and (cstatus == 0).all()) yield (geom, poly_space_base, qp_weights, mesh, ir, ic, ap, ps, rrc, rcells[0, 1], crc, ccells[0, 1], vec, edofs, fdofs)
def distribute_fields_dofs(fields, cell_tasks, is_overlap=True, use_expand_dofs=False, save_inter_regions=False, output_dir=None, comm=None, verbose=False): """ Distribute the owned cells and DOFs of the given field to all tasks. Uses interleaved PETSc numbering in each task, i.e., the PETSc DOFs of each tasks are consecutive and correspond to the first field DOFs block followed by the second etc. Expand DOFs to equations if `use_expand_dofs` is True. """ if comm is None: comm = PETSc.COMM_WORLD size = comm.size if comm.rank == 0: gfds = [] inter_facets = get_inter_facets(fields[0].domain, cell_tasks) for field in fields: aux = create_task_dof_maps(field, cell_tasks, inter_facets, is_overlap=is_overlap, use_expand_dofs=use_expand_dofs, save_inter_regions=save_inter_regions, output_dir=output_dir) cell_parts = aux[2] n_cell_parts = [len(ii) for ii in cell_parts] output('numbers of cells in tasks (without overlaps):', n_cell_parts, verbose=verbose) assert_(sum(n_cell_parts) == field.domain.mesh.n_el) assert_(nm.all(nm.array(n_cell_parts) > 0)) gfd = Struct(name='global field %s distribution' % field.name, dof_maps=aux[0], id_map=aux[1], cell_parts=aux[2], overlap_cells=aux[3], coffsets=nm.empty(size, dtype=nm.int32)) gfds.append(gfd) # Initialize composite offsets of DOFs. if len(fields) > 1: # Renumber id_maps for field inter-leaving. offset = 0 for ir in range(size): for ii, gfd in enumerate(gfds): dof_map = gfd.dof_maps[ir] n_owned = dof_map[3] off = dof_map[4] iown = nm.concatenate([dof_map[0]] + dof_map[1]) gfd.id_map[iown] += offset - off gfd.coffsets[ir] = offset offset += n_owned else: gfd = gfds[0] gfd.coffsets[:] = [gfd.dof_maps[ir][4] for ir in range(size)] else: gfds = [None] * len(fields) lfds = [] for ii, field in enumerate(fields): aux = distribute_field_dofs(field, gfds[ii], use_expand_dofs=use_expand_dofs, comm=comm, verbose=verbose) lfd = Struct(name='local field %s distribution' % field.name, cells=aux[0], petsc_dofs_range=aux[1], petsc_dofs_conn=aux[2]) lfds.append(lfd) return lfds, gfds
def verify_task_dof_maps(dof_maps, id_map, field, use_expand_dofs=False, verbose=False): """ Verify the counts and values of DOFs in `dof_maps` and `id_map` corresponding to `field`. Returns the vector with a task number for each DOF. """ timer = Timer(start=True) if verbose: output('verifying...') output('total number of DOFs:', field.n_nod) output('number of tasks:', len(dof_maps)) count = count2 = 0 dofs = [] if use_expand_dofs: vec = nm.empty(field.n_nod * field.n_components, dtype=nm.float64) else: vec = nm.empty(field.n_nod, dtype=nm.float64) for ir, dof_map in ordered_iteritems(dof_maps): n_owned = dof_map[3] offset = dof_map[4] o2 = offset + n_owned if verbose: output('task %d: %d owned on offset %d' % (ir, n_owned, offset)) if not use_expand_dofs: aux = dof_map[0] assert_(nm.all((id_map[aux] >= offset) & (id_map[aux] < o2))) count2 += dof_map[3] count += len(dof_map[0]) dofs.append(dof_map[0]) vec[dof_map[0]] = ir for aux in dof_map[1]: if not use_expand_dofs: assert_(nm.all((id_map[aux] >= offset) & (id_map[aux] < o2))) count += len(aux) dofs.append(aux) vec[aux] = ir dofs = nm.concatenate(dofs) n_dof = vec.shape[0] assert_(n_dof == len(dofs)) if not expand_dofs: assert_(nm.all(nm.sort(dofs) == nm.sort(id_map))) dofs = nm.unique(dofs) assert_(n_dof == len(dofs)) assert_(n_dof == dofs[-1] + 1) assert_(n_dof == count) assert_(n_dof == count2) assert_(n_dof == len(id_map)) assert_(n_dof == len(nm.unique(id_map))) output('...done in', timer.stop(), verbose=verbose) return vec
def classify_args(self): """ Classify types of the term arguments and find matching call signature. A state variable can be in place of a parameter variable and vice versa. """ self.names = Struct(name='arg_names', material=[], variable=[], user=[], state=[], virtual=[], parameter=[]) # Prepare for 'opt_material' - just prepend a None argument if needed. if isinstance(self.arg_types[0], tuple): arg_types = self.arg_types[0] else: arg_types = self.arg_types if len(arg_types) == (len(self.args) + 1): self.args.insert(0, (None, None)) self.arg_names.insert(0, (None, None)) if isinstance(self.arg_types[0], tuple): assert_(len(self.modes) == len(self.arg_types)) # Find matching call signature using variable arguments - material # and user arguments are ignored! matched = [] for it, arg_types in enumerate(self.arg_types): arg_kinds = get_arg_kinds(arg_types) if self._check_variables(arg_kinds): matched.append((it, arg_kinds)) if len(matched) == 1: i_match, arg_kinds = matched[0] arg_types = self.arg_types[i_match] self.mode = self.modes[i_match] elif len(matched) == 0: msg = 'cannot match arguments! (%s)' % self.arg_names raise ValueError(msg) else: msg = 'ambiguous arguments! (%s)' % self.arg_names raise ValueError(msg) else: arg_types = self.arg_types arg_kinds = get_arg_kinds(self.arg_types) self.mode = Struct.get(self, 'mode', None) if not self._check_variables(arg_kinds): raise ValueError('cannot match variables! (%s)' % self.arg_names) # Set actual argument types. self.ats = list(arg_types) for ii, arg_kind in enumerate(arg_kinds): name = self.arg_names[ii] if arg_kind.endswith('variable'): names = self.names.variable if arg_kind == 'virtual_variable': self.names.virtual.append(name) elif arg_kind == 'state_variable': self.names.state.append(name) elif arg_kind == 'parameter_variable': self.names.parameter.append(name) elif arg_kind.endswith('material'): # This should be better checked already in create_arg_parser(). if not isinstance(name, tuple): raise ValueError('wrong material argument %s of term %s!' % (name, self.get_str())) names = self.names.material else: names = self.names.user names.append(name) self.n_virtual = len(self.names.virtual) if self.n_virtual > 1: raise ValueError('at most one virtual variable is allowed! (%d)' % self.n_virtual) self.set_arg_types() self.setup_integration()
def plot_velocity(source, ctp, bbox, position, family, kind, name, seed='sphere', type='ribbon', integration_direction='both', seed_scale=1.0, seed_resolution=20, widget_enabled=True, color_kind=None, color_name=None, opacity=1.0, **kwargs): """ Show velocity field by displaying streamlines and optionally a surface plot given by quantity `color_name`. Parameters ---------- seed : one of ('sphere', 'point', 'line', 'plane') The streamline seed name. type : one of ('line', 'ribbon', 'tube') The streamline seed line type. integration_direction : one of ('forward', 'backward', 'both') The stream tracer integration direction. seed_scale : float The seed size scale. seed_resolution : int The number of seed points in a direction (depends on `seed`). widget_enabled : bool It True, the seed widget is visible and can be interacted with. color_kind : str, optional The kind of data determining the colormap. color_name : str, optional The name of data determining the colormap. opacity : float The surface plot opacity. **kwargs : dict Additional keyword arguments for attributes of `streamline.seed.widget`. """ assert_(kind == 'vectors') active_v = mlab.pipeline.set_active_attribute(source) active_v.point_vectors_name = name active_n = mlab.pipeline.extract_vector_norm(active_v) s = mlab.pipeline.streamline streamline = s(active_n, seedtype=seed, linetype=type, seed_visible=True, seed_scale=seed_scale, integration_direction=integration_direction, seed_resolution=seed_resolution) streamline.update_streamlines = True streamline.seed.widget.enabled = widget_enabled streamline.actor.actor.position = position for key, val in six.iteritems(kwargs): setattr(streamline.seed.widget, key, val) if color_name is None: active = active_n else: new_name, active = _get_scalars(color_name, color_kind, source) surf = mlab.pipeline.surface(active, opacity=opacity) surf.actor.actor.position = position if color_name is not None: mm = active.children[0] lm = mm.scalar_lut_manager scalar_bars = [['point', new_name, lm]] active_v.point_vectors_name = name # This is needed to have # colors by velocity! return kind, name, active_n, scalar_bars else: return kind, name, active_n
def __init__(self, name, regions, dof_names, dof_map_fun, constraints, variables, ts=None, functions=None): MRLCBCOperator.__init__(self, name, regions, dof_names, dof_map_fun, variables, functions=functions) import sympy as sm n_c = self.field.n_components dpn = len(self.dof_names) n_nod = self.mdofs.shape[0] assert_(dpn <= n_c) if (isinstance(constraints, basestr) or isinstance(constraints, Function)): fun = get_condition_value(constraints, functions, 'nodal', 'constraints') coors = self.field.get_coor(self.mdofs) mtx, rhs = fun(ts, coors, self.region) else: mtx, rhs = constraints mtx = nm.tile(mtx, (n_nod, 1, 1)) rhs = nm.tile(rhs, (n_nod, 1)) n_ceq = mtx.shape[1] assert_(n_ceq == rhs.shape[1]) assert_(dpn == mtx.shape[2]) assert_(n_ceq <= dpn) data = [] rows = [] cols = [] rhss = nm.zeros(n_nod * dpn, dtype=nm.float64) n_new = 0 us = [sm.Symbol('u%d' % ii) for ii in range(dpn)] for im, nmtx in enumerate(mtx): eqs = sm.Matrix(nmtx) * sm.Matrix(us) - rhs[im][:, None] sol = sm.solve(eqs) assert_(len(sol) == n_ceq) imasters = [] ifixed = [] islaves = set() ccs = [] for key, _poly in six.iteritems(sol): imaster = int(key.name[1:]) imasters.append(imaster) if not isinstance(_poly, sm.Float): poly = _poly.as_poly() # Workaround for poly.all_coeffs() not applicable to # multivariate polynomials. coefs = [] for ii, uu in enumerate(us): if poly.has(uu): coefs.append(poly.coeff_monomial(uu)) islaves.add(ii) coefs.append(poly.TC()) ccs.append(coefs) else: # Degenerated constraint - fixed master. ifixed.append(imaster) ccs.append([float(_poly)]) islaves = sorted(islaves) for ii, imaster in enumerate(imasters): coefs = ccs[ii] em = dpn * im + imaster rhss[em] = coefs[-1] if imaster in ifixed: continue # Master DOF is expressed in terms of slave DOFs. for ii, islave in enumerate(islaves): es = ii + n_new rows.append(em) cols.append(es) data.append(coefs[ii]) # Slave DOFs are copied. for ii, islave in enumerate(islaves): em = dpn * im + islave es = ii + n_new rows.append(em) cols.append(es) data.append(1.0) n_new += len(islaves) rows = nm.array(rows, dtype=nm.int32) cols = nm.array(cols, dtype=nm.int32) data = nm.array(data, dtype=nm.float64) mtx = sp.coo_matrix((data, (rows, cols)), shape=(n_nod * dpn, n_new)) self.n_mdof = n_nod * dpn self.n_new_dof = n_new self.mtx = mtx.tocsr() self.rhs = rhss
def get_fargs(self, material, virtual, mode=None, term_mode=None, diff_var=None, **kwargs): assert_(virtual.n_components == 1) geo, _ = self.get_mapping(virtual) return material, geo.bf, geo
def describe_dual_surface(self, surface): n_fa, n_edge = surface.n_fa, self.sgel.n_edge mesh_coors = self.mesh_coors # Face centres. fcoors = mesh_coors[surface.econn] centre_coors = nm.dot(self.bf.squeeze(), fcoors) surface_coors = mesh_coors[surface.nodes] dual_coors = nm.r_[surface_coors, centre_coors] coor_offset = surface.nodes.shape[0] # Normals in primary mesh nodes. nodal_normals = compute_nodal_normals(surface.nodes, self.region, self.field) ee = surface.leconn[:, self.sgel.edges].copy() edges_per_face = ee.copy() sh = edges_per_face.shape ee.shape = edges_per_face.shape = (sh[0] * sh[1], sh[2]) edges_per_face.sort(axis=1) eo = nm.empty((sh[0] * sh[1], ), dtype=nm.object) eo[:] = [tuple(ii) for ii in edges_per_face] ueo, e_sort, e_id = unique(eo, return_index=True, return_inverse=True) ueo = edges_per_face[e_sort] # edge centre, edge point 1, face centre, edge point 2 conn = nm.empty((n_edge * n_fa, 4), dtype=nm.int32) conn[:, 0] = e_id conn[:, 1] = ee[:, 0] conn[:,2] = nm.repeat(nm.arange(n_fa, dtype=nm.int32), n_edge) \ + coor_offset conn[:, 3] = ee[:, 1] # face centre, edge point 2, edge point 1 tri_conn = nm.ascontiguousarray(conn[:, [2, 1, 3]]) # Ensure orientation - outward normal. cc = dual_coors[tri_conn] v1 = cc[:, 1] - cc[:, 0] v2 = cc[:, 2] - cc[:, 0] normals = nm.cross(v1, v2) nn = nodal_normals[surface.leconn].sum(axis=1).repeat(n_edge, 0) centre_normals = (1.0 / surface.n_fp) * nn centre_normals /= la.norm_l2_along_axis(centre_normals)[:, None] dot = nm.sum(normals * centre_normals, axis=1) assert_((dot > 0.0).all()) # Prepare mapping from reference triangle e_R to a # triangle within reference face e_D. gel = self.gel.surface_facet ref_coors = gel.coors ref_centre = nm.dot(self.bf.squeeze(), ref_coors) cc = nm.r_[ref_coors, ref_centre[None, :]] rconn = nm.empty((n_edge, 3), dtype=nm.int32) rconn[:, 0] = gel.n_vertex rconn[:, 1] = gel.edges[:, 0] rconn[:, 2] = gel.edges[:, 1] map_er_ed = VolumeMapping(cc, rconn, gel=gel) # Prepare mapping from reference triangle e_R to a # physical triangle e. map_er_e = SurfaceMapping(dual_coors, tri_conn, gel=gel) # Compute triangle basis (edge) vectors. nn = surface.nodes[ueo] edge_coors = mesh_coors[nn] edge_centre_coors = 0.5 * edge_coors.sum(axis=1) edge_normals = 0.5 * nodal_normals[ueo].sum(axis=1) edge_normals /= la.norm_l2_along_axis(edge_normals)[:, None] nn = surface.nodes[ueo] edge_dirs = edge_coors[:, 1] - edge_coors[:, 0] edge_dirs /= la.norm_l2_along_axis(edge_dirs)[:, None] edge_ortho = nm.cross(edge_normals, edge_dirs) edge_ortho /= la.norm_l2_along_axis(edge_ortho)[:, None] # Primary face - dual sub-faces map. # i-th row: indices to conn corresponding to sub-faces of i-th face. face_map = nm.arange(n_fa * n_edge, dtype=nm.int32) face_map.shape = (n_fa, n_edge) # The actual connectivity for assembling (unique nodes per master # faces). asm_conn = e_id[face_map] n_nod = ueo.shape[0] # One node per unique edge. n_components = self.dim - 1 dual_surface = Struct(name='dual_surface_description', dim=self.dim, n_dual_fa=conn.shape[0], n_dual_fp=self.dim, n_fa=n_fa, n_edge=n_edge, n_nod=n_nod, n_components=n_components, n_dof=n_nod * n_components, dual_coors=dual_coors, coor_offset=coor_offset, e_sort=e_sort, conn=conn, tri_conn=tri_conn, map_er_e=map_er_e, map_er_ed=map_er_ed, face_map=face_map, asm_conn=asm_conn, nodal_normals=nodal_normals, edge_centre_coors=edge_centre_coors, edge_normals=edge_normals, edge_dirs=edge_dirs, edge_ortho=edge_ortho) return dual_surface
def gen_misc_mesh(mesh_dir, force_create, kind, args, suffix='.mesh', verbose=False): """ Create sphere or cube mesh according to `kind` in the given directory if it does not exist and return path to it. """ import os from sfepy import data_dir defdir = os.path.join(data_dir, 'meshes') if mesh_dir is None: mesh_dir = defdir def retype(args, types, defaults): args = list(args) args.extend(defaults[len(args):len(defaults)]) return tuple([type(value) for type, value in zip(types, args)]) if kind == 'sphere': default = [5, 41, args[0]] args = retype(args, [float, int, float], default) mesh_pattern = os.path.join(mesh_dir, 'sphere-%.2f-%.2f-%i') else: assert_(kind == 'cube') args = retype(args, (int, float, int, float, int, float), (args[0], args[1], args[0], args[1], args[0], args[1])) mesh_pattern = os.path.join(mesh_dir, 'cube-%i_%.2f-%i_%.2f-%i_%.2f') if verbose: output(args) filename = mesh_pattern % args if not force_create: if os.path.exists(filename): return filename if os.path.exists(filename + '.mesh'): return filename + '.mesh' if os.path.exists(filename + '.vtk'): return filename + '.vtk' if kind == 'cube': filename = filename + suffix ensure_path(filename) output('creating new cube mesh') output('(%i nodes in %.2f) x (%i nodes in %.2f) x (%i nodes in %.2f)' % args) output('to file %s...' % filename) mesh = gen_block_mesh(args[1::2], args[0::2], (0.0, 0.0, 0.0), name=filename) mesh.write(filename, io='auto') output('...done') else: import subprocess filename = filename + '.mesh' ensure_path(filename) output('creating new sphere mesh (%i nodes, r=%.2f) and gradation %d' % args) output('to file %s...' % filename) f = open(os.path.join(defdir, 'quantum', 'sphere.geo')) tmpfile = os.path.join(data_dir, 'tmp', 'sphere.geo.temp') ff = open(tmpfile, "w") ff.write(""" R = %i.0; n = %i.0; dens = %f; """ % args) ff.write(f.read()) f.close() ff.close() subprocess.call( ['gmsh', '-3', tmpfile, '-format', 'mesh', '-o', filename]) output('...done') return filename
def _eval_basis_transform(self, subs): """ """ from sfepy.discrete import Integral from sfepy.discrete.fem import Mesh, FEDomain, Field transform = nm.tile(nm.eye(self.econn.shape[1]), (self.econn.shape[0], 1, 1)) if subs is None: return transform gel = self.gel ao = self.approx_order conn = [gel.conn] mesh = Mesh.from_data('a', gel.coors, None, [conn], [nm.array([0])], [gel.name]) cdomain = FEDomain('d', mesh) comega = cdomain.create_region('Omega', 'all') rcfield = Field.from_args('rc', self.dtype, 1, comega, approx_order=ao) fdomain = cdomain.refine() fomega = fdomain.create_region('Omega', 'all') rffield = Field.from_args('rf', self.dtype, 1, fomega, approx_order=ao) def assign_transform(transform, bf, subs, ef): if not len(subs): return n_sub = (subs.shape[1] - 2) // 2 for ii, sub in enumerate(subs): for ij in range(n_sub): ik = 2 * (ij + 1) fface = ef[sub[ik + 1]] mtx = transform[sub[ik]] ix, iy = nm.meshgrid(fface, fface) cbf = bf[iy, 0, ix] mtx[ix, iy] = cbf fcoors = rffield.get_coor() coors = fcoors[rffield.econn[0]] integral = Integral('i', coors=coors, weights=nm.ones_like(coors[:, 0])) rcfield.clear_qp_base() bf = rcfield.get_base('v', False, integral) if gel.name == '2_4': fsubs = subs esubs = None assign_transform(transform, bf, fsubs, rffield.efaces) else: fsubs = subs[0] esubs = subs[1] assign_transform(transform, bf, fsubs, rffield.efaces) if esubs is not None: assign_transform(transform, bf, esubs, rffield.eedges) assert_((nm.abs(transform.sum(1) - 1.0) < 1e-15).all()) return transform
def map_equations(self, bcs, field, ts, functions, problem=None, warn=False): """ Create the mapping of active DOFs from/to all DOFs. Parameters ---------- bcs : Conditions instance The Dirichlet or periodic boundary conditions (single condition instances). The dof names in the conditions must already be canonized. field : Field instance The field of the variable holding the DOFs. ts : TimeStepper instance The time stepper. functions : Functions instance The registered functions. problem : Problem instance, optional The problem that can be passed to user functions as a context. warn : bool, optional If True, warn about BC on non-existent nodes. Returns ------- active_bcs : set The set of boundary conditions active in the current time. Notes ----- - Periodic bc: master and slave DOFs must belong to the same field (variables can differ, though). """ if bcs is None: self._init_empty(field) return set() eq_ebc = nm.zeros((self.var_di.n_dof,), dtype=nm.int32) val_ebc = nm.zeros((self.var_di.n_dof,), dtype=field.dtype) master_slave = nm.zeros((self.var_di.n_dof,), dtype=nm.int32) chains = [] active_bcs = set() for bc in bcs: # Skip conditions that are not active in the current time. if not is_active_bc(bc, ts=ts, functions=functions): continue active_bcs.add(bc.key) if isinstance(bc, DGEssentialBC): ntype = "DGEBC" region = bc.region elif isinstance(bc, DGPeriodicBC): ntype = "DGEPBC" region = bc.regions[0] elif isinstance(bc, EssentialBC): ntype = 'EBC' region = bc.region elif isinstance(bc, PeriodicBC): ntype = 'EPBC' region = bc.regions[0] if warn: clean_msg = ('warning: ignoring nonexistent %s node (%s) in ' % (ntype, self.var_di.var_name)) else: clean_msg = None # Get master region nodes. master_nod_list = field.get_dofs_in_region(region) if len(master_nod_list) == 0: continue if ntype == 'EBC': # EBC. dofs, val = bc.dofs ## # Evaluate EBC values. fun = get_condition_value(val, functions, 'EBC', bc.name) if isinstance(fun, Function): aux = fun fun = lambda coors: aux(ts, coors, bc=bc, problem=problem) nods, vv = field.set_dofs(fun, region, len(dofs), clean_msg) eq = expand_nodes_to_equations(nods, dofs, self.dof_names) # Duplicates removed here... eq_ebc[eq] = 1 if vv is not None: val_ebc[eq] = nm.ravel(vv) elif ntype == "DGEBC": dofs, val = bc.dofs ## # Evaluate EBC values. fun = get_condition_value(val, functions, 'EBC', bc.name) if isinstance(fun, Function): aux = fun fun = lambda coors: aux(ts, coors, bc=bc, problem=problem) values = field.get_bc_facet_values(fun, region, diff=bc.diff) bc2bfi = field.get_bc_facet_idx(region) self.dg_ebc_val.setdefault(bc.diff, []).append(values) self.dg_ebc.setdefault(bc.diff, []).append(bc2bfi) self.n_dg_ebc += 1 elif ntype == "DGEPBC": # ensure matching boundaries? master_bc2bfi = field.get_bc_facet_idx(region) slave_bc2bfi = field.get_bc_facet_idx(bc.regions[1]) self.dg_epbc.append((master_bc2bfi, slave_bc2bfi)) self.n_dg_epbc += 1 else: # EPBC. region = bc.regions[1] slave_nod_list = field.get_dofs_in_region(region) nmaster = nm.unique(master_nod_list) # Treat fields not covering the whole domain. if nmaster[0] == -1: nmaster = nmaster[1:] nslave = nm.unique(slave_nod_list) # Treat fields not covering the whole domain. if nslave[0] == -1: nslave = nslave[1:] ## print nmaster + 1 ## print nslave + 1 if nmaster.shape != nslave.shape: msg = 'EPBC list lengths do not match!\n(%s,\n %s)' %\ (nmaster, nslave) raise ValueError(msg) if (nmaster.shape[0] == 0) and (nslave.shape[0] == 0): continue mcoor = field.get_coor(nmaster) scoor = field.get_coor(nslave) fun = get_condition_value(bc.match, functions, 'EPBC', bc.name) if isinstance(fun, Function): i1, i2 = fun(mcoor, scoor) else: i1, i2 = fun ## print nm.c_[mcoor[i1], scoor[i2]] ## print nm.c_[nmaster[i1], nslave[i2]] + 1 meq = expand_nodes_to_equations(nmaster[i1], bc.dofs[0], self.dof_names) seq = expand_nodes_to_equations(nslave[i2], bc.dofs[1], self.dof_names) m_assigned = nm.where(master_slave[meq] != 0)[0] s_assigned = nm.where(master_slave[seq] != 0)[0] if m_assigned.size or s_assigned.size: # Chain EPBC. aux = master_slave[meq[m_assigned]] sgn = nm.sign(aux) om_chain = zip(meq[m_assigned], (aux - sgn) * sgn) chains.extend(om_chain) aux = master_slave[seq[s_assigned]] sgn = nm.sign(aux) os_chain = zip(seq[s_assigned], (aux - sgn) * sgn) chains.extend(os_chain) m_chain = zip(meq[m_assigned], seq[m_assigned]) chains.extend(m_chain) msd = nm.setdiff1d(s_assigned, m_assigned) s_chain = zip(meq[msd], seq[msd]) chains.extend(s_chain) msa = nm.union1d(m_assigned, s_assigned) ii = nm.setdiff1d(nm.arange(meq.size), msa) master_slave[meq[ii]] = seq[ii] + 1 master_slave[seq[ii]] = - meq[ii] - 1 else: master_slave[meq] = seq + 1 master_slave[seq] = - meq - 1 chains = group_chains(chains) resolve_chains(master_slave, chains) self.master = nm.nonzero(master_slave > 0)[0] self.slave = master_slave[self.master] - 1 # Propagate EBCs via PBCs. mask = eq_ebc[self.master] > 0 im0 = self.master[mask] im1 = self.slave[mask] mask = eq_ebc[self.slave] > 0 is0 = self.slave[mask] is1 = self.master[mask] val_ebc[im1] = val_ebc[im0] eq_ebc[im1] = eq_ebc[im0] val_ebc[is1] = val_ebc[is0] eq_ebc[is1] = eq_ebc[is0] self.eq_ebc = nm.nonzero(eq_ebc > 0)[0] self.val_ebc = val_ebc[self.eq_ebc] assert_((self.eq_ebc.shape == self.val_ebc.shape)) self.eq[self.eq_ebc] = -2 self.eq[self.master] = -1 self._mark_unused(field) self.eqi = self.eq[self.eq >= 0] self.eq[self.eqi] = nm.arange(self.eqi.shape[0], dtype=nm.int32) self.eq[self.master] = self.eq[self.slave] self.n_eq = self.eqi.shape[0] self.n_ebc = self.eq_ebc.shape[0] self.n_epbc = self.master.shape[0] return active_bcs
def main(): parser = ArgumentParser(description=__doc__) parser.add_argument('--version', action='version', version='%(prog)s') parser.add_argument('-b', '--basis', metavar='name', action='store', dest='basis', default='lagrange', help=help['basis']) parser.add_argument('-n', '--max-order', metavar='order', type=int, action='store', dest='max_order', default=10, help=help['max_order']) parser.add_argument('-m', '--matrix', metavar='type', action='store', dest='matrix_type', default='laplace', help=help['matrix_type']) parser.add_argument('-g', '--geometry', metavar='name', action='store', dest='geometry', default='2_4', help=help['geometry']) options = parser.parse_args() dim, n_ep = int(options.geometry[0]), int(options.geometry[2]) output('reference element geometry:') output(' dimension: %d, vertices: %d' % (dim, n_ep)) n_c = {'laplace': 1, 'elasticity': dim}[options.matrix_type] output('matrix type:', options.matrix_type) output('number of variable components:', n_c) output('polynomial space:', options.basis) output('max. order:', options.max_order) mesh = Mesh.from_file(data_dir + '/meshes/elements/%s_1.mesh' % options.geometry) domain = FEDomain('domain', mesh) omega = domain.create_region('Omega', 'all') orders = nm.arange(1, options.max_order + 1, dtype=nm.int) conds = [] order_fix = 0 if options.geometry in ['2_4', '3_8'] else 1 for order in orders: output('order:', order, '...') field = Field.from_args('fu', nm.float64, n_c, omega, approx_order=order, space='H1', poly_space_base=options.basis) to = field.approx_order quad_order = 2 * (max(to - order_fix, 0)) output('quadrature order:', quad_order) integral = Integral('i', order=quad_order) qp, _ = integral.get_qp(options.geometry) output('number of quadrature points:', qp.shape[0]) u = FieldVariable('u', 'unknown', field) v = FieldVariable('v', 'test', field, primary_var_name='u') m = Material('m', D=stiffness_from_lame(dim, 1.0, 1.0), mu=1.0) if options.matrix_type == 'laplace': term = Term.new('dw_laplace(m.mu, v, u)', integral, omega, m=m, v=v, u=u) n_zero = 1 else: assert_(options.matrix_type == 'elasticity') term = Term.new('dw_lin_elastic(m.D, v, u)', integral, omega, m=m, v=v, u=u) n_zero = (dim + 1) * dim / 2 term.setup() output('assembling...') tt = time.clock() mtx, iels = term.evaluate(mode='weak', diff_var='u') output('...done in %.2f s' % (time.clock() - tt)) mtx = mtx[0, 0] try: assert_(nm.max(nm.abs(mtx - mtx.T)) < 1e-10) except: from sfepy.base.base import debug debug() output('matrix shape:', mtx.shape) eigs = eig(mtx, method='eig.sgscipy', eigenvectors=False) eigs.sort() # Zero 'true' zeros. eigs[:n_zero] = 0.0 ii = nm.where(eigs < 0.0)[0] if len(ii): output('matrix is not positive semi-definite!') ii = nm.where(eigs[n_zero:] < 1e-12)[0] if len(ii): output('matrix has more than %d zero eigenvalues!' % n_zero) output('smallest eigs:\n', eigs[:10]) ii = nm.where(eigs > 0.0)[0] emin, emax = eigs[ii[[0, -1]]] output('min:', emin, 'max:', emax) cond = emax / emin conds.append(cond) output('condition number:', cond) output('...done') plt.figure(1) plt.semilogy(orders, conds) plt.xticks(orders, orders) plt.xlabel('polynomial order') plt.ylabel('condition number') plt.grid() plt.figure(2) plt.loglog(orders, conds) plt.xticks(orders, orders) plt.xlabel('polynomial order') plt.ylabel('condition number') plt.grid() plt.show()
def set_dofs(self, fun=0.0, region=None, dpn=None, warn=None): """ Set the values of DOFs given by the `region` using a function of space coordinates or value `fun`. If `fun` is a function, the l2 projection that is global for all region facets is used to set the DOFs. If `dpn > 1`, and `fun` is a function, it has to return the values DOF-by-DOF, i.e. a single one-dimensional vector with all values of the first component, then of the second one etc. concatenated together. Parameters ---------- fun : float or array of length dpn or callable The DOF values. region : Region The region containing the DOFs. dpn : int, optional The DOF-per-node count. If not given, the number of field components is used. warn : str, optional The warning message printed when the region selects no DOFs. Returns ------- nods : array, shape (n_dof,) The field DOFs (or node indices) given by the region. vals : array, shape (dpn, n_dof) The values of the DOFs, DOF-by-DOF when raveled in C (row-major) order. """ if region is None: region = self.region if dpn is None: dpn = self.n_components nods = [] vals = [] aux = self.get_dofs_in_region(region) nods = nm.unique(nm.hstack(aux)) if nm.isscalar(fun): vals = nm.repeat([fun], nods.shape[0] * dpn) elif isinstance(fun, nm.ndarray): assert_(len(fun) == dpn) vals = nm.repeat(fun, nods.shape[0]) elif callable(fun): import scipy.sparse as sps from sfepy.solvers.ls import solve from sfepy.discrete.integrals import Integral from sfepy.discrete.fem.utils import prepare_remap import sfepy.discrete.iga as iga from sfepy.discrete.iga.extmods.igac import eval_mapping_data_in_qp nurbs = self.nurbs facets = self._get_facets(region.kind_tdim) # Region facet connectivity. rconn = self.get_econn('surface', region) # Local connectivity. remap = prepare_remap(nods, nods.max() + 1) lconn = [remap[ii] for ii in rconn] # Cell and face(cell) ids for each facet. fis = region.get_facet_indices() # Integral given by max. NURBS surface degree. fdegrees = iga.get_surface_degrees(nurbs.degrees) order = fdegrees.max() integral = Integral('i', order=2 * order) vals, weights = integral.get_qp(self.domain.gel.surface_facet_name) # Boundary QP - use tensor product structure. bvals = iga.create_boundary_qp(vals, region.tdim) # Compute facet basis, jacobians and physical BQP. n_dof = len(nods) rhs = nm.zeros((dpn, n_dof), dtype=nm.float64) rows, cols, mvals = [], [], [] all_qp = [] all_fbfs = [] all_dets = [] for ii, (ie, ifa) in enumerate(fis): qp_coors = bvals[ifa] bfs, _, dets = eval_mapping_data_in_qp(qp_coors, nurbs.cps, nurbs.weights, nurbs.degrees, nurbs.cs, nurbs.conn, nm.array([ie])) # Facet basis. fbfs = bfs[..., facets[ifa]][0, :, 0, :] # Weight Jacobians by quadrature point weights. dets = nm.abs(dets) * weights[None, :, None, None] dets = dets[0, :, 0, :] # Physical BQP. fcps = nurbs.cps[nurbs.conn[ie, facets[ifa]]] qp = nm.dot(fbfs, fcps) all_qp.append(qp) all_fbfs.append(fbfs) all_dets.append(dets) # DOF values in the physical BQP. qps = nm.concatenate(all_qp) vals = nm.asarray(fun(qps)) vals.shape = (dpn, qps.shape[0]) n_qp_face = len(bvals[0]) # Assemble l2 projection system. for ii, (ie, ifa) in enumerate(fis): # Assembling indices. elc = lconn[ii] fvals = vals[:, n_qp_face * ii:n_qp_face * (ii + 1)] fbfs = all_fbfs[ii] dets = all_dets[ii] # Local projection system. for idof in xrange(dpn): lrhs = (fbfs * (fvals[idof, :, None] * dets)).sum(0) rhs[idof, elc] += lrhs lmtx = ((fbfs[..., None] * fbfs[:, None, :]) * dets[..., None]).sum(0) er, ec = nm.meshgrid(elc, elc) rows.append(er.ravel()) cols.append(ec.ravel()) mvals.append(lmtx.ravel()) rows = nm.concatenate(rows) cols = nm.concatenate(cols) mvals = nm.concatenate(mvals) mtx = sps.coo_matrix((mvals, (rows, cols)), shape=(n_dof, n_dof)) vals = nm.zeros((dpn, n_dof), dtype=nm.float64) # Solve l2 projection system. for idof in xrange(dpn): dofs = solve(mtx, rhs[idof, :]) vals[idof, remap[nods]] = dofs else: raise ValueError('unknown function/value type! (%s)' % type(fun)) return nods, vals
def main(): from sfepy import data_dir parser = OptionParser(usage=usage, version='%prog') parser.add_option('--diffusivity', metavar='float', type=float, action='store', dest='diffusivity', default=1e-5, help=helps['diffusivity']) parser.add_option('--ic-max', metavar='float', type=float, action='store', dest='ic_max', default=2.0, help=helps['ic_max']) parser.add_option('--order', metavar='int', type=int, action='store', dest='order', default=2, help=helps['order']) parser.add_option('-r', '--refine', metavar='int', type=int, action='store', dest='refine', default=0, help=helps['refine']) parser.add_option('-p', '--probe', action="store_true", dest='probe', default=False, help=helps['probe']) parser.add_option('-s', '--show', action="store_true", dest='show', default=False, help=helps['show']) options, args = parser.parse_args() assert_((0 < options.order), 'temperature approximation order must be at least 1!') output('using values:') output(' diffusivity:', options.diffusivity) output(' max. IC value:', options.ic_max) output('uniform mesh refinement level:', options.refine) mesh = Mesh.from_file(data_dir + '/meshes/3d/cylinder.mesh') domain = FEDomain('domain', mesh) if options.refine > 0: for ii in xrange(options.refine): output('refine %d...' % ii) domain = domain.refine() output('... %d nodes %d elements' % (domain.shape.n_nod, domain.shape.n_el)) omega = domain.create_region('Omega', 'all') left = domain.create_region('Left', 'vertices in x < 0.00001', 'facet') right = domain.create_region('Right', 'vertices in x > 0.099999', 'facet') field = Field.from_args('fu', nm.float64, 'scalar', omega, approx_order=options.order) T = FieldVariable('T', 'unknown', field, history=1) s = FieldVariable('s', 'test', field, primary_var_name='T') m = Material('m', diffusivity=options.diffusivity * nm.eye(3)) integral = Integral('i', order=2 * options.order) t1 = Term.new('dw_diffusion(m.diffusivity, s, T)', integral, omega, m=m, s=s, T=T) t2 = Term.new('dw_volume_dot(s, dT/dt)', integral, omega, s=s, T=T) eq = Equation('balance', t1 + t2) eqs = Equations([eq]) # Boundary conditions. ebc1 = EssentialBC('T1', left, {'T.0': 2.0}) ebc2 = EssentialBC('T2', right, {'T.0': -2.0}) # Initial conditions. def get_ic(coors, ic): x, y, z = coors.T return 2 - 40.0 * x + options.ic_max * nm.sin(4 * nm.pi * x / 0.1) ic_fun = Function('ic_fun', get_ic) ic = InitialCondition('ic', omega, {'T.0': ic_fun}) ls = ScipyDirect({}) nls_status = IndexedStruct() nls = Newton({'is_linear': True}, lin_solver=ls, status=nls_status) pb = Problem('heat', equations=eqs, nls=nls, ls=ls) pb.set_bcs(ebcs=Conditions([ebc1, ebc2])) pb.set_ics(Conditions([ic])) tss = SimpleTimeSteppingSolver({ 't0': 0.0, 't1': 100.0, 'n_step': 11 }, problem=pb) tss.init_time() if options.probe: # Prepare probe data. probes, labels = gen_lines(pb) ev = pb.evaluate order = 2 * (options.order - 1) gfield = Field.from_args('gu', nm.float64, 'vector', omega, approx_order=options.order - 1) dvel = FieldVariable('dvel', 'parameter', gfield, primary_var_name='(set-to-None)') cfield = Field.from_args('gu', nm.float64, 'scalar', omega, approx_order=options.order - 1) component = FieldVariable('component', 'parameter', cfield, primary_var_name='(set-to-None)') nls_options = {'eps_a': 1e-16, 'i_max': 1} if options.show: plt.ion() # Solve the problem using the time stepping solver. suffix = tss.ts.suffix for step, time, state in tss(): if options.probe: # Probe the solution. dvel_qp = ev('ev_diffusion_velocity.%d.Omega(m.diffusivity, T)' % order, copy_materials=False, mode='qp') project_by_component(dvel, dvel_qp, component, order, nls_options=nls_options) all_results = [] for ii, probe in enumerate(probes): fig, results = probe_results(ii, T, dvel, probe, labels[ii]) all_results.append(results) plt.tight_layout() fig.savefig('time_poisson_interactive_probe_%s.png' % (suffix % step), bbox_inches='tight') if options.show: plt.draw() for ii, results in enumerate(all_results): output('probe %d (%s):' % (ii, probes[ii].name)) output.level += 2 for key, res in ordered_iteritems(results): output(key + ':') val = res[1] output(' min: %+.2e, mean: %+.2e, max: %+.2e' % (val.min(), val.mean(), val.max())) output.level -= 2
def get_graph_conns(self, any_dof_conn=False, rdcs=None, cdcs=None, active_only=True): """ Get DOF connectivities needed for creating tangent matrix graph. Parameters ---------- any_dof_conn : bool By default, only volume DOF connectivities are used, with the exception of trace surface DOF connectivities. If True, any kind of DOF connectivities is allowed. rdcs, cdcs : arrays, optional Additional row and column DOF connectivities, corresponding to the variables used in the equations. active_only : bool If True, the active DOF connectivities have reduced size and are created with the reduced (active DOFs only) numbering. Returns ------- rdcs, cdcs : arrays The row and column DOF connectivities defining the matrix graph blocks. """ if rdcs is None: rdcs = [] cdcs = [] elif cdcs is None: cdcs = copy(rdcs) else: assert_(len(rdcs) == len(cdcs)) if rdcs is cdcs: # Make sure the lists are not the same object. rdcs = copy(rdcs) adcs = self.variables.adof_conns # Only volume dof connectivities are used, with the exception of trace # surface dof connectivities. shared = set() for key, ii, info in iter_dict_of_lists(self.conn_info, return_keys=True): rvar, cvar = info.virtual, info.state if (rvar is None) or (cvar is None): continue is_surface = rvar.is_surface or cvar.is_surface dct = info.dc_type.type if not (dct in ('volume', 'scalar', 'custom') or is_surface or info.is_trace or any_dof_conn): continue rreg_name = info.get_region_name(can_trace=False) creg_name = info.get_region_name() rname = rvar.get_primary_name() rkey = (rname, rreg_name, dct, False) ckey = (cvar.name, creg_name, dct, info.is_trace) dc_key = (rkey, ckey) if not dc_key in shared: rdc = adcs[rkey] cdc = adcs[ckey] if not active_only: ii = nm.where(rdc < 0) rdc = rdc.copy() rdc[ii] = -1 - rdc[ii] ii = nm.where(cdc < 0) cdc = cdc.copy() cdc[ii] = -1 - cdc[ii] rdcs.append(rdc) cdcs.append(cdc) shared.add(dc_key) return rdcs, cdcs
def _region_leaf(level, op): token, details = op['token'], op['orig'] if token != 'KW_Region': parse_def = token + '<' + ' '.join(details) + '>' region = Region('leaf', rdef, domain, parse_def=parse_def) if token == 'KW_Region': details = details[1][2:] aux = regions.find(details) if not aux: raise ValueError('region %s does not exist' % details) else: if rdef[:4] == 'copy': region = aux.copy() else: region = aux elif token == 'KW_All': region.vertices = nm.arange(n_coor, dtype=nm.uint32) elif token == 'E_VIR': where = details[2] if where[0] == '[': vertices = nm.array(eval(where), dtype=nm.uint32) assert_(nm.amin(vertices) >= 0) assert_(nm.amax(vertices) < n_coor) else: coors = domain.cmesh.coors y = z = None x = coors[:, 0] if dim > 1: y = coors[:, 1] if dim > 2: z = coors[:, 2] coor_dict = {'x': x, 'y': y, 'z': z} vertices = nm.where(eval(where, {}, coor_dict))[0] region.vertices = vertices elif token == 'E_VOS': facets = domain.cmesh.get_surface_facets() region.set_kind('facet') region.facets = facets elif token == 'E_VBF': where = details[2] coors = domain.cmesh.coors fun = functions[where] vertices = fun(coors, domain=domain) region.vertices = vertices elif token == 'E_CBF': where = details[2] coors = domain.get_centroids(dim) fun = functions[where] cells = fun(coors, domain=domain) region.cells = cells elif token == 'E_COG': group = int(details[3]) region.cells = nm.where(domain.cmesh.cell_groups == group)[0] elif token == 'E_COSET': raise NotImplementedError('element sets not implemented!') elif token == 'E_VOG': group = int(details[3]) region.vertices = nm.where(domain.cmesh.vertex_groups == group)[0] elif token == 'E_VOSET': try: vertices = domain.vertex_set_bcs[details[3]] except KeyError: msg = 'undefined vertex set! (%s)' % details[3] raise ValueError(msg) region.vertices = vertices elif token == 'E_OVIR': aux = regions[details[3][2:]] region.vertices = aux.vertices[0:1] elif token == 'E_VI': region.vertices = nm.array([int(ii) for ii in details[1:]], dtype=nm.uint32) elif token == 'E_CI': region.cells = nm.array([int(ii) for ii in details[1:]], dtype=nm.uint32) else: output('token "%s" unkown - check regions!' % token) raise NotImplementedError return region
def define(dims=(3, 1, 0.5), shape=(11, 15, 15), u_order=1, refine=0, ls='ls_d', u_inlet=None, mode='lcbc', term_mode='original', backend='numpy', optimize='optimal', verbosity=0): """ Parameters ---------- dims : tuple The block domain dimensions. shape : tuple The mesh resolution: increase to improve accuracy. u_order : int The velocity field approximation order. refine : int The refinement level. ls : 'ls_d' or 'ls_i' The pre-configured linear solver name. u_inlet : float, optional The x-component of the inlet velocity. mode : 'lcbc' or 'penalty' The alternative formulations. term_mode : 'original' or 'einsum' The switch to use either the original or new experimental einsum-based terms. backend : str The einsum mode backend. optimize : str The einsum mode optimization (backend dependent). verbosity : 0, 1, 2, 3 The verbosity level of einsum-based terms. """ output('dims: {}, shape: {}, u_order: {}, refine: {}, u_inlet: {}'.format( dims, shape, u_order, refine, u_inlet)) output('linear solver: {}'.format(ls)) output('mode: {}, term_mode: {}'.format(mode, term_mode)) if term_mode == 'einsum': output('backend: {}, optimize: {}, verbosity: {}'.format( backend, optimize, verbosity)) assert_(mode in {'lcbc', 'penalty'}) assert_(term_mode in {'original', 'einsum'}) if u_order > 1: assert_(mode == 'penalty', msg='set mode=penalty to use u_order > 1!') dims = nm.array(dims, dtype=nm.float64) shape = nm.array(shape, dtype=nm.int32) def mesh_hook(mesh, mode): """ Generate the block mesh. """ if mode == 'read': mesh = gen_block_mesh(dims, shape, [0, 0, 0], name='user_block', verbose=False) return mesh elif mode == 'write': pass filename_mesh = UserMeshIO(mesh_hook) regions = define_box_regions(3, 0.5 * dims) regions.update({ 'Omega': 'all', 'Edges_v': ("""(r.Near *v r.Bottom) +v (r.Bottom *v r.Far) +v (r.Far *v r.Top) +v (r.Top *v r.Near)""", 'edge'), 'Gamma1_f': ('copy r.Top', 'face'), 'Gamma2_f': ('r.Near +v r.Bottom +v r.Far', 'face'), 'Gamma_f': ('r.Gamma1_f +v r.Gamma2_f', 'face'), 'Gamma_v': ('r.Gamma_f -v r.Edges_v', 'face'), 'Inlet_f': ('r.Left -v r.Gamma_f', 'face'), }) fields = { 'velocity': ('real', 3, 'Omega', u_order), 'pressure': ('real', 1, 'Omega', 1), } def get_u_d(ts, coors, region=None): """ Given stator velocity. """ out = nm.zeros_like(coors) out[:] = [1.0, 1.0, 0.0] return out functions = { 'get_u_d': (get_u_d, ), } variables = { 'u': ('unknown field', 'velocity', 0), 'v': ('test field', 'velocity', 'u'), 'u_d': ('parameter field', 'velocity', { 'setter': 'get_u_d' }), 'p': ('unknown field', 'pressure', 1), 'q': ('test field', 'pressure', 'p'), } materials = { 'm': ({ 'nu': 1e-3, 'beta': 1e-2, 'mu': 1e-10, }, ), } ebcs = {} if u_inlet is not None: ebcs['inlet'] = ('Inlet_f', {'u.0': u_inlet, 'u.[1, 2]': 0.0}) if mode == 'lcbc': lcbcs = { 'walls': ('Gamma_v', { 'u.all': None }, None, 'no_penetration', 'normals_Gamma.vtk'), 'edges': ('Edges_v', [(-0.5, 1.5)], { 'u.all': None }, None, 'edge_direction', 'edges_Edges.vtk'), } if term_mode == 'original': equations = { 'balance': """dw_div_grad.5.Omega(m.nu, v, u) - dw_stokes.5.Omega(v, p) + dw_dot.5.Gamma1_f(m.beta, v, u) + dw_dot.5.Gamma2_f(m.beta, v, u) = + dw_dot.5.Gamma1_f(m.beta, v, u_d)""", 'incompressibility': """dw_laplace.5.Omega(m.mu, q, p) + dw_stokes.5.Omega(u, q) = 0""", } else: equations = { 'balance': """de_div_grad.5.Omega(m.nu, v, u) - de_stokes.5.Omega(v, p) + de_dot.5.Gamma1_f(m.beta, v, u) + de_dot.5.Gamma2_f(m.beta, v, u) = + de_dot.5.Gamma1_f(m.beta, v, u_d)""", 'incompressibility': """de_laplace.5.Omega(m.mu, q, p) + de_stokes.5.Omega(u, q) = 0""", } else: materials['m'][0]['np_eps'] = 1e3 if term_mode == 'original': equations = { 'balance': """dw_div_grad.5.Omega(m.nu, v, u) - dw_stokes.5.Omega(v, p) + dw_dot.5.Gamma1_f(m.beta, v, u) + dw_dot.5.Gamma2_f(m.beta, v, u) + dw_non_penetration_p.5.Gamma1_f(m.np_eps, v, u) + dw_non_penetration_p.5.Gamma2_f(m.np_eps, v, u) = + dw_dot.5.Gamma1_f(m.beta, v, u_d)""", 'incompressibility': """dw_laplace.5.Omega(m.mu, q, p) + dw_stokes.5.Omega(u, q) = 0""", } else: equations = { 'balance': """de_div_grad.5.Omega(m.nu, v, u) - de_stokes.5.Omega(v, p) + de_dot.5.Gamma1_f(m.beta, v, u) + de_dot.5.Gamma2_f(m.beta, v, u) + de_non_penetration_p.5.Gamma1_f(m.np_eps, v, u) + de_non_penetration_p.5.Gamma2_f(m.np_eps, v, u) = + de_dot.5.Gamma1_f(m.beta, v, u_d)""", 'incompressibility': """de_laplace.5.Omega(m.mu, q, p) + de_stokes.5.Omega(u, q) = 0""", } solvers = { 'ls_d': ('ls.auto_direct', {}), 'ls_i': ( 'ls.petsc', { 'method': 'bcgsl', # ksp_type 'precond': 'bjacobi', # pc_type 'sub_precond': 'ilu', # sub_pc_type 'eps_a': 0.0, # abstol 'eps_r': 1e-12, # rtol 'eps_d': 1e10, # Divergence tolerance. 'i_max': 200, # maxits }), 'newton': ('nls.newton', { 'i_max': 1, 'eps_a': 1e-10, }), } options = { 'nls': 'newton', 'ls': ls, 'eterm': { 'verbosity': verbosity, 'backend_args': { 'backend': backend, 'optimize': optimize, 'layout': None, }, }, 'refinement_level': refine, } return locals()
def get_simplex_circumcentres(coors, force_inside_eps=None): """ Compute the circumcentres of `n_s` simplices in 1D, 2D and 3D. Parameters ---------- coors : array The coordinates of the simplices with `n_v` vertices given in an array of shape `(n_s, n_v, dim)`, where `dim` is the space dimension and `2 <= n_v <= (dim + 1)`. force_inside_eps : float, optional If not None, move the circumcentres that are outside of their simplices or closer to their boundary then `force_inside_eps` so that they are inside the simplices at the distance given by `force_inside_eps`. It is ignored for edges. Returns ------- centres : array The circumcentre coordinates as an array of shape `(n_s, dim)`. """ n_s, n_v, dim = coors.shape assert_(2 <= n_v <= (dim + 1)) assert_(1 <= dim <= 3) if n_v == 2: # Edges. centres = 0.5 * nm.sum(coors, axis=1) else: if n_v == 3: # Triangles. a2 = norm(coors[:,1,:] - coors[:,2,:], squared=True) b2 = norm(coors[:,0,:] - coors[:,2,:], squared=True) c2 = norm(coors[:,0,:] - coors[:,1,:], squared=True) bar_coors = nm.c_[a2 * (-a2 + b2 + c2), b2 * (a2 - b2 + c2), c2 * (a2 + b2 - c2)] elif n_v == 4: # Tetrahedrons. a2 = norm(coors[:,2,:] - coors[:,1,:], squared=True) b2 = norm(coors[:,2,:] - coors[:,0,:], squared=True) c2 = norm(coors[:,1,:] - coors[:,0,:], squared=True) d2 = norm(coors[:,3,:] - coors[:,0,:], squared=True) e2 = norm(coors[:,3,:] - coors[:,1,:], squared=True) f2 = norm(coors[:,3,:] - coors[:,2,:], squared=True) bar_coors = nm.c_[(d2 * a2 * (f2 + e2 - a2) + b2 * e2 * (a2 + f2 - e2) + c2 * f2 * (e2 + a2 - f2) - 2 * a2 * e2 * f2), (e2 * b2 * (f2 + d2 - b2) + c2 * f2 * (d2 + b2 - f2) + a2 * d2 * (b2 + f2 - d2) - 2 * b2 * d2 * f2), (f2 * c2 * (e2 + d2 - c2) + b2 * e2 * (d2 + c2 - e2) + a2 * d2 * (c2 + e2 - d2) - 2 * c2 * e2 * d2), (d2 * a2 * (b2 + c2 - a2) + e2 * b2 * (c2 + a2 - b2) + f2 * c2 * (a2 + b2 - c2) - 2 * a2 * b2 * c2)] else: raise ValueError('unsupported simplex! (%d vertices)' % n_v) bar_coors /= nm.sum(bar_coors, axis=1)[:,None] if force_inside_eps is not None: bc = 1.0 / n_v limit = 0.9 * bc bar_centre = nm.array([bc] * n_v, dtype=nm.float64) eps = float(force_inside_eps) if eps > limit: output('force_inside_eps is too big, adjusting! (%e -> %e)' % (eps, limit)) eps = limit # Flag is True where the barycentre is closer to the simplex # boundary then eps, or outside of the simplex. mb = nm.min(bar_coors, axis=1) flag = nm.where(mb < eps)[0] # Move the bar_coors[flag] towards bar_centre so that it is # inside at the eps distance. mb = mb[flag] alpha = ((eps - mb) / (bar_centre[0] - mb))[:,None] bar_coors[flag] = (1.0 - alpha) * bar_coors[flag] \ + alpha * bar_centre[None,:] centres = transform_bar_to_space_coors(bar_coors, coors) return centres
def call_mlab(self, scene=None, show=True, is_3d=False, view=None, roll=None, parallel_projection=False, fgcolor=(0.0, 0.0, 0.0), bgcolor=(1.0, 1.0, 1.0), colormap='blue-red', layout='rowcol', scalar_mode='iso_surface', vector_mode='arrows_norm', rel_scaling=None, clamping=False, ranges=None, is_scalar_bar=False, is_wireframe=False, opacity=None, subdomains_args=None, rel_text_width=None, fig_filename='view.png', resolution=None, filter_names=None, only_names=None, group_names=None, step=None, time=None, anti_aliasing=None, domain_specific=None): """ By default, all data (point, cell, scalars, vectors, tensors) are plotted in a grid layout, except data named 'node_groups', 'mat_id' which are usually not interesting. Parameters ---------- show : bool Call mlab.show(). is_3d : bool If True, use scalar cut planes instead of surface for certain datasets. Also sets 3D view mode. view : tuple Azimuth, elevation angles, distance and focal point as in `mlab.view()`. roll : float Roll angle tuple as in mlab.roll(). parallel_projection: bool If True, use parallel projection. fgcolor : tuple of floats (R, G, B) The foreground color, that is the color of all text annotation labels (axes, orientation axes, scalar bar labels). bgcolor : tuple of floats (R, G, B) The background color. colormap : str The colormap name. layout : str Grid layout for placing the datasets. Possible values are: 'row', 'col', 'rowcol', 'colrow'. scalar_mode : str Mode for plotting scalars and tensor magnitudes, one of 'cut_plane', 'iso_surface', 'both'. vector_mode : str Mode for plotting vectors, one of 'arrows', 'norm', 'arrows_norm', 'warp_norm'. rel_scaling : float Relative scaling of glyphs for vector datasets. clamping : bool Clamping for vector datasets. ranges : dict List of data ranges in the form {name : (min, max), ...}. is_scalar_bar : bool If True, show a scalar bar for each data. is_wireframe : bool If True, show a wireframe of mesh surface bar for each data. opacity : float Global surface and wireframe opacity setting in [0.0, 1.0], subdomains_args : tuple Tuple of (mat_id_name, threshold_limits, single_color), see :func:`add_subdomains_surface`, or None. rel_text_width : float Relative text width. fig_filename : str File name for saving the resulting scene figure. resolution : tuple Scene and figure resolution. If None, it is set automatically according to the layout. filter_names : list of strings Omit the listed datasets. If None, it is initialized to ['node_groups', 'mat_id']. Pass [] if you need no filtering. only_names : list of strings Draw only the listed datasets. If None, it is initialized all names besides those in filter_names. group_names : list of tuples List of data names in the form [(name1, ..., nameN), (...)]. Plots of data named in each group are superimposed. Repetitions of names are possible. step : int, optional If not None, the time step to display. The closest higher step is used if the desired one is not available. Has precedence over `time`. time : float, optional If not None, the time of the time step to display. The closest higher time is used if the desired one is not available. anti_aliasing : int Value of anti-aliasing. domain_specific : dict Domain-specific drawing functions and configurations. """ self.fgcolor = fgcolor self.bgcolor = bgcolor self.colormap = colormap if filter_names is None: filter_names = ['node_groups', 'mat_id'] if rel_text_width is None: rel_text_width = 0.02 if isinstance(scalar_mode, basestr): if scalar_mode == 'both': scalar_mode = ('cut_plane', 'iso_surface') elif scalar_mode in ('cut_plane', 'iso_surface'): scalar_mode = (scalar_mode, ) else: raise ValueError('bad value of scalar_mode parameter! (%s)' % scalar_mode) else: for sm in scalar_mode: if not sm in ('cut_plane', 'iso_surface'): raise ValueError( 'bad value of scalar_mode parameter! (%s)' % sm) if isinstance(vector_mode, basestr): if vector_mode == 'arrows_norm': vector_mode = ('arrows', 'norm') elif vector_mode == 'warp_norm': vector_mode = ('warp', 'norm') elif vector_mode in ('arrows', 'norm'): vector_mode = (vector_mode, ) elif vector_mode == 'cut_plane': if is_3d: vector_mode = ('cut_plane', ) else: vector_mode = ('arrows', ) else: raise ValueError('bad value of vector_mode parameter! (%s)' % vector_mode) else: for vm in vector_mode: if not vm in ('arrows', 'norm', 'warp'): raise ValueError( 'bad value of vector_mode parameter! (%s)' % vm) mlab.options.offscreen = self.offscreen self.size_hint = self.get_size_hint(layout, resolution=resolution) is_new_scene = False if scene is not None: if scene is not self.scene: is_new_scene = True self.scene = scene gui = None else: if (self.scene is not None) and (not self.scene.running): self.scene = None if self.scene is None: if self.offscreen or not show: gui = None scene = mlab.figure(fgcolor=fgcolor, bgcolor=bgcolor, size=self.size_hint) else: gui = ViewerGUI(viewer=self, fgcolor=fgcolor, bgcolor=bgcolor) scene = gui.scene.mayavi_scene if scene is not self.scene: is_new_scene = True self.scene = scene else: gui = self.gui scene = self.scene self.engine = mlab.get_engine() self.engine.current_scene = self.scene self.gui = gui self.file_source = create_file_source(self.filename, watch=self.watch, offscreen=self.offscreen) steps, times = self.file_source.get_ts_info() has_several_times = len(times) > 1 has_several_steps = has_several_times or (len(steps) > 1) if gui is not None: gui.has_several_steps = has_several_steps self.reload_source = reload_source = ReloadSource() reload_source._viewer = self reload_source._source = self.file_source if has_several_steps: self.set_step = set_step = SetStep() set_step._viewer = self set_step._source = self.file_source if step is not None: step = step if step >= 0 else steps[-1] + step + 1 assert_(steps[0] <= step <= steps[-1], msg='invalid time step! (%d <= %d <= %d)' % (steps[0], step, steps[-1])) set_step.step = step elif time is not None: assert_(times[0] <= time <= times[-1], msg='invalid time! (%e <= %e <= %e)' % (times[0], time, times[-1])) set_step.time = time else: set_step.step = steps[0] if self.watch: self.file_source.setup_notification(set_step, 'file_changed') if gui is not None: gui.set_step = set_step else: if self.watch: self.file_source.setup_notification(reload_source, 'reload_source') self.options.update(get_arguments(omit=['self', 'file_source'])) if gui is None: self.render_scene(scene, self.options) self.reset_view() if is_scalar_bar: self.show_scalar_bars(self.scalar_bars) else: traits_view = View( Item( 'scene', editor=SceneEditor(scene_class=MayaviScene), show_label=False, width=self.size_hint[0], height=self.size_hint[1], style='custom', ), Group( Item('set_step', defined_when='set_step is not None', show_label=False, style='custom'), ), HGroup( spring, Item('button_make_snapshots_steps', show_label=False, enabled_when='has_several_steps == True'), Item('button_make_animation_steps', show_label=False, enabled_when='has_several_steps == True'), spring, Item('button_make_snapshots_times', show_label=False, enabled_when='has_several_steps == True'), Item('button_make_animation_times', show_label=False, enabled_when='has_several_steps == True'), spring, ), HGroup(spring, Item('button_reload', show_label=False), Item('button_view', show_label=False), Item('button_quit', show_label=False)), resizable=True, buttons=[], handler=ClosingHandler(), ) if is_new_scene: if show: gui.configure_traits(view=traits_view) else: gui.edit_traits(view=traits_view) return gui
def _build_rhs( self, sols ): for sol in sols.itervalues(): assert_( len( sol ) == 3 ) return sols
def define(dim=2, use_ebcs=True): assert_(dim in (2, 3)) if dim == 2: filename_mesh = data_dir + '/meshes/2d/square_quad.mesh' else: filename_mesh = data_dir + '/meshes/3d/cube_medium_tetra.mesh' options = { 'nls': 'newton', 'ls': 'ls', 'post_process_hook': 'post_process' } def get_constraints(ts, coors, region=None): mtx = nm.ones((coors.shape[0], 1, dim), dtype=nm.float64) rhs = nm.arange(coors.shape[0], dtype=nm.float64)[:, None] rhs *= 0.1 / (coors.shape[0] - 1) return mtx, rhs functions = { 'get_constraints': (get_constraints, ), } fields = { 'displacement': ('real', dim, 'Omega', 1), } materials = { 'm': ({ 'D': stiffness_from_lame(dim, lam=5.769, mu=3.846), }, ), 'load': ({ 'val': -1.0 }, ), } variables = { 'u': ('unknown field', 'displacement', 0), 'v': ('test field', 'displacement', 'u'), } regions = { 'Omega': 'all', 'Bottom': ('vertices in (y < -0.499) -v r.Left', 'facet'), 'Top': ('vertices in (y > 0.499) -v r.Left', 'facet'), 'Left': ('vertices in (x < -0.499)', 'facet'), 'Right': ('vertices in (x > 0.499) -v (r.Bottom +v r.Top)', 'facet'), } if dim == 2: lcbcs = { 'nlcbc1': ('Top', { 'u.all': None }, None, 'nodal_combination', ([[1.0, -1.0]], [0.0])), 'nlcbc2': ('Bottom', { 'u.all': None }, None, 'nodal_combination', ([[1.0, 1.0]], [-0.1])), 'nlcbc3': ('Right', { 'u.all': None }, None, 'nodal_combination', 'get_constraints'), } else: lcbcs = { 'nlcbc1': ('Top', { 'u.all': None }, None, 'nodal_combination', ([[1.0, -1.0, 1.0], [1.0, 0.5, 0.1]], [0.0, 0.05])), 'nlcbc2': ('Bottom', { 'u.[2,1]': None }, None, 'nodal_combination', ([[1.0, -0.1]], [0.2])), 'nlcbc3': ('Right', { 'u.all': None }, None, 'nodal_combination', 'get_constraints'), } if use_ebcs: ebcs = { 'fix': ('Left', { 'u.all': 0.0 }), } else: ebcs = {} lcbcs.update({ 'nlcbc4': ('Left', { 'u.all': None }, None, 'nodal_combination', (nm.eye(dim), nm.zeros(dim))), }) equations = { 'elasticity': """ dw_lin_elastic.2.Omega(m.D, v, u) = -dw_surface_ltr.2.Right(load.val, v) """, } solvers = { 'ls': ('ls.scipy_direct', {}), 'newton': ('nls.newton', { 'i_max': 1, 'eps_a': 1e-10, }), } return locals()
def __call__(self, rhs, x0=None, conf=None, eps_a=None, eps_r=None, i_max=None, mtx=None, status=None, **kwargs): import os, sys, shutil, tempfile from sfepy import base_dir, data_dir from sfepy.base.ioutils import ensure_path eps_a = get_default(eps_a, self.conf.eps_a) eps_r = get_default(eps_r, self.conf.eps_r) i_max = get_default(i_max, self.conf.i_max) eps_d = self.conf.eps_d petsc = self.petsc # There is no use in caching matrix in the solver - always set as new. pmtx, psol, prhs = self.set_matrix(mtx) ksp = self.ksp ksp.setOperators(pmtx) ksp.setFromOptions() # PETSc.Options() not used yet... ksp.setTolerances(atol=eps_a, rtol=eps_r, divtol=eps_d, max_it=i_max) output_dir = tempfile.mkdtemp() # Set PETSc rhs, solve, get solution from PETSc solution. if x0 is not None: psol[...] = x0 sol0_filename = os.path.join(output_dir, 'sol0.dat') else: sol0_filename = '' prhs[...] = rhs script_filename = os.path.join(base_dir, 'solvers/petsc_worker.py') mtx_filename = os.path.join(output_dir, 'mtx.dat') rhs_filename = os.path.join(output_dir, 'rhs.dat') sol_filename = os.path.join(output_dir, 'sol.dat') status_filename = os.path.join(output_dir, 'status.txt') log_filename = os.path.join(data_dir, 'tmp/sol.log') ensure_path(log_filename) output('storing system to %s...' % output_dir) tt = time.clock() view_mtx = petsc.Viewer().createBinary(mtx_filename, mode='w') view_rhs = petsc.Viewer().createBinary(rhs_filename, mode='w') pmtx.view(view_mtx) prhs.view(view_rhs) if sol0_filename: view_sol0 = petsc.Viewer().createBinary(sol0_filename, mode='w') psol.view(view_sol0) output('...done in %.2f s' % (time.clock() - tt)) command = [ 'mpiexec -n %d' % self.conf.n_proc, sys.executable, script_filename, '-mtx %s' % mtx_filename, '-rhs %s' % rhs_filename, '-sol0 %s' % sol0_filename, '-sol %s' % sol_filename, '-status %s' % status_filename, '-ksp_type %s' % self.conf.method, '-pc_type %s' % self.conf.precond, '-sub_pc_type %s' % self.conf.sub_precond, '-ksp_atol %.3e' % self.conf.eps_a, '-ksp_rtol %.3e' % self.conf.eps_r, '-ksp_max_it %d' % self.conf.i_max, '-ksp_monitor %s' % log_filename, '-ksp_view %s' % log_filename, ] if self.conf.precond_side is not None: command.append('-ksp_pc_side %s' % self.conf.precond_side) out = os.system(" ".join(command)) assert_(out == 0) output('reading solution...') tt = time.clock() view_sol = self.petsc.Viewer().createBinary(sol_filename, mode='r') psol = petsc.Vec().load(view_sol) fd = open(status_filename, 'r') line = fd.readline().split() reason = int(line[0]) elapsed = float(line[1]) fd.close() output('...done in %.2f s' % (time.clock() - tt)) sol = psol[...].copy() output('%s(%s, %s/proc) convergence: %s (%s)' % (self.conf.method, self.conf.precond, self.conf.sub_precond, reason, self.converged_reasons[reason])) output('elapsed: %.2f [s]' % elapsed) shutil.rmtree(output_dir) return sol