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): timer = Timer(start=True) 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) elapsed = timer.stop() if status is not None: status['time'] = elapsed status['n_iter'] = self.ksp.getIterationNumber() return result
def presolve(self, mtx): """Prepare A^{-1} B^T for the Schur complement.""" mtx_a = mtx['A'] mtx_bt = mtx['BT'] output('full A size: %.3f MB' % (8.0 * nm.prod(mtx_a.shape) / 1e6)) output('full B size: %.3f MB' % (8.0 * nm.prod(mtx_bt.shape) / 1e6)) ls = Solver.any_from_conf(self.problem.ls_conf + Struct(use_presolve=True), mtx=mtx_a) if self.mode == 'explicit': timer = Timer(start=True) mtx_aibt = nm.zeros(mtx_bt.shape, dtype=mtx_bt.dtype) for ic in range(mtx_bt.shape[1]): mtx_aibt[:, ic] = ls(mtx_bt[:, ic].toarray().squeeze()) output('mtx_aibt: %.2f s' % timer.stop()) action_aibt = MatrixAction.from_array(mtx_aibt) else: ## # c: 30.08.2007, r: 13.02.2008 def fun_aibt(vec): # Fix me for sparse mtx_bt... rhs = sc.dot(mtx_bt, vec) out = ls(rhs) return out action_aibt = MatrixAction.from_function( fun_aibt, (mtx_a.shape[0], mtx_bt.shape[1]), nm.float64) mtx['action_aibt'] = action_aibt
def _standard_ts_call(self, vec0=None, nls=None, init_fun=None, prestep_fun=None, poststep_fun=None, status=None, **kwargs): timer = Timer(start=True) nls = get_default(nls, self.nls, 'nonlinear solver has to be specified!') init_fun = get_default(init_fun, lambda ts, vec0: vec0) prestep_fun = get_default(prestep_fun, lambda ts, vec: None) poststep_fun = get_default(poststep_fun, lambda ts, vec: None) result = call(self, vec0=vec0, nls=nls, init_fun=init_fun, prestep_fun=prestep_fun, poststep_fun=poststep_fun, status=status, **kwargs) elapsed = timer.stop() if status is not None: status['time'] = elapsed status['n_step'] = self.ts.n_step return result
def _standard_call(self, mtx_m, mtx_d, mtx_k, n_eigs=None, eigenvectors=None, status=None, conf=None, **kwargs): timer = Timer(start=True) conf = get_default(conf, self.conf) mtx_m = get_default(mtx_m, self.mtx_m) mtx_d = get_default(mtx_d, self.mtx_d) mtx_k = get_default(mtx_k, self.mtx_k) n_eigs = get_default(n_eigs, self.n_eigs) eigenvectors = get_default(eigenvectors, self.eigenvectors) status = get_default(status, self.status) result = call(self, mtx_m, mtx_d, mtx_k, n_eigs, eigenvectors, status, conf, **kwargs) elapsed = timer.stop() if status is not None: status['time'] = elapsed return result
def time_update(self, ts, equations, mode='normal', problem=None, verbose=True): """ Update material parameters for given time, problem, and equations. Parameters ---------- ts : TimeStepper instance The time stepper. equations : Equations instance The equations using the materials. mode : 'normal', 'update' or 'force' The update mode, see :func:`Material.time_update()`. problem : Problem instance, optional The problem that can be passed to user functions as a context. verbose : bool If False, reduce verbosity. """ if verbose: output('updating materials...') timer = Timer(start=True) for mat in self: if verbose: output(' ', mat.name) mat.time_update(ts, equations, mode=mode, problem=problem) if verbose: output('...done in %.2f s' % timer.stop())
def create_regions(self, region_defs, functions=None, allow_empty=False): output('creating regions...') timer = Timer(start=True) self.reset_regions() ## # Sort region definitions by dependencies. graph, name_to_sort_name = get_dependency_graph(region_defs) sorted_regions = sort_by_dependency(graph) ## # Define regions. for name in sorted_regions: sort_name = name_to_sort_name[name] rdef = region_defs[sort_name] region = self.create_region(name, rdef.select, kind=rdef.get('kind', 'cell'), parent=rdef.get('parent', None), check_parents=False, extra_options=rdef.get( 'extra_options', None), functions=functions, allow_empty=allow_empty) output(' ', region.name) output('...done in %.2f s' % timer.stop()) return self.regions
def _standard_call(self, mtx_a, mtx_b=None, n_eigs=None, eigenvectors=None, status=None, conf=None, **kwargs): timer = Timer(start=True) conf = get_default(conf, self.conf) mtx_a = get_default(mtx_a, self.mtx_a) mtx_b = get_default(mtx_b, self.mtx_b) n_eigs = get_default(n_eigs, self.n_eigs) eigenvectors = get_default(eigenvectors, self.eigenvectors) status = get_default(status, self.status) if n_eigs == 0: result = self._ret_zero(mtx_a, eigenvectors=eigenvectors) else: result = call(self, mtx_a, mtx_b, n_eigs, eigenvectors, status, conf, **kwargs) elapsed = timer.stop() if status is not None: status['time'] = elapsed return result
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): timer = Timer(start=True) 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. elapsed = timer.stop() if status is not None: status['time'] = elapsed status['n_iter'] = n_iter return result
def __call__(self, vec_x0, conf=None, fun=None, fun_grad=None, lin_solver=None, iter_hook=None, status=None): if conf is not None: self.set_method(conf) else: conf = self.conf fun = get_default(fun, self.fun) status = get_default(status, self.status) timer = Timer(start=True) kwargs = {'iter' : conf.i_max, 'alpha' : conf.alpha, 'verbose' : conf.verbose} if conf.method == 'broyden_generalized': kwargs.update({'M' : conf.M}) elif conf.method in ['anderson', 'anderson2']: kwargs.update({'M' : conf.M, 'w0' : conf.w0}) if conf.method in ['anderson', 'anderson2', 'broyden', 'broyden2' , 'newton_krylov']: kwargs.update({'f_tol' : conf.f_tol }) vec_x = self.solver(fun, vec_x0, **kwargs) vec_x = nm.asarray(vec_x) if status is not None: status['time_stats'] = timer.stop() return vec_x
def create_conn_graph(self, verbose=True): """ Create a graph of mesh connectivity. Returns ------- graph : csr_matrix The mesh connectivity graph as a SciPy CSR matrix. """ from sfepy.discrete.common.extmods.cmesh import create_mesh_graph shape = (self.n_nod, self.n_nod) output('graph shape:', shape, verbose=verbose) if nm.prod(shape) == 0: output('no graph (zero size)!', verbose=verbose) return None output('assembling mesh graph...', verbose=verbose) timer = Timer(start=True) conn = self.get_conn(self.descs[0]) nnz, prow, icol = create_mesh_graph(shape[0], shape[1], 1, [conn], [conn]) output('...done in %.2f s' % timer.stop(), verbose=verbose) output('graph nonzeros: %d (%.2e%% fill)' \ % (nnz, float(nnz) / nm.prod(shape)), verbose=verbose) data = nm.ones((nnz,), dtype=nm.bool) graph = sp.csr_matrix((data, icol, prow), shape) return graph
def assemble_mtx_to_petsc(pmtx, mtx, pdofs, drange, is_overlap=True, comm=None, verbose=False): """ Assemble a local CSR matrix to a global PETSc matrix. """ if comm is None: comm = PETSc.COMM_WORLD timer = Timer() lgmap = PETSc.LGMap().create(pdofs, comm=comm) pmtx.setLGMap(lgmap, lgmap) if is_overlap: output('setting matrix values...', verbose=verbose) timer.start() mask = (pdofs < drange[0]) | (pdofs >= drange[1]) nnz_per_row = nm.diff(mtx.indptr) mtx2 = mtx.copy() mtx2.data[nm.repeat(mask, nnz_per_row)] = 0 mtx2.eliminate_zeros() pmtx.setValuesLocalCSR(mtx2.indptr, mtx2.indices, mtx2.data, PETSc.InsertMode.INSERT_VALUES) output('...done in', timer.stop(), verbose=verbose) output('assembling matrix...', verbose=verbose) timer.start() pmtx.assemble() output('...done in', timer.stop(), verbose=verbose) else: output('setting matrix values...', verbose=verbose) timer.start() pmtx.setValuesLocalCSR(mtx.indptr, mtx.indices, mtx.data, PETSc.InsertMode.ADD_VALUES) output('...done in', timer.stop(), verbose=verbose) output('assembling matrix...', verbose=verbose) timer.start() pmtx.assemble() output('...done in', timer.stop(), verbose=verbose)
def solve_eigen_problem(self): opts = self.app_options pb = self.problem pb.set_equations(pb.conf.equations) pb.time_update() output('assembling lhs...') timer = Timer(start=True) mtx_a = pb.evaluate(pb.conf.equations['lhs'], mode='weak', auto_init=True, dw_mode='matrix') output('...done in %.2f s' % timer.stop()) if 'rhs' in pb.conf.equations: output('assembling rhs...') timer.start() mtx_b = pb.evaluate(pb.conf.equations['rhs'], mode='weak', dw_mode='matrix') output('...done in %.2f s' % timer.stop()) else: mtx_b = None _n_eigs = get_default(opts.n_eigs, mtx_a.shape[0]) output('solving eigenvalue problem for {} values...'.format(_n_eigs)) eig = Solver.any_from_conf(pb.get_solver_conf(opts.evps)) if opts.eigs_only: eigs = eig(mtx_a, mtx_b, opts.n_eigs, eigenvectors=False) svecs = None else: eigs, svecs = eig(mtx_a, mtx_b, opts.n_eigs, eigenvectors=True) output('...done') vecs = self.make_full(svecs) self.save_results(eigs, vecs) return Struct(pb=pb, eigs=eigs, vecs=vecs)
def assemble_rhs_to_petsc(prhs, rhs, pdofs, drange, is_overlap=True, comm=None, verbose=False): """ Assemble a local right-hand side vector to a global PETSc vector. """ if comm is None: comm = PETSc.COMM_WORLD timer = Timer() if is_overlap: output('setting rhs values...', verbose=verbose) timer.start() rdofs = nm.where((pdofs < drange[0]) | (pdofs >= drange[1]), -1, pdofs) prhs.setOption(prhs.Option.IGNORE_NEGATIVE_INDICES, True) prhs.setValues(rdofs, rhs, PETSc.InsertMode.INSERT_VALUES) output('...done in', timer.stop(), verbose=verbose) output('assembling rhs...', verbose=verbose) timer.start() prhs.assemble() output('...done in', timer.stop(), verbose=verbose) else: output('setting rhs values...', verbose=verbose) timer.start() prhs.setValues(pdofs, rhs, PETSc.InsertMode.ADD_VALUES) output('...done in', timer.stop(), verbose=verbose) output('assembling rhs...', verbose=verbose) timer.start() prhs.assemble() output('...done in', timer.stop(), verbose=verbose)
def from_file(filename=None, io='auto', prefix_dir=None, omit_facets=False, file_format=None): """ Read a mesh from a file. Parameters ---------- filename : string or function or MeshIO instance or Mesh instance The name of file to read the mesh from. For convenience, a mesh creation function or a MeshIO instance or directly a Mesh instance can be passed in place of the file name. io : *MeshIO instance Passing *MeshIO instance has precedence over filename. prefix_dir : str If not None, the filename is relative to that directory. omit_facets : bool If True, do not read cells of lower dimension than the space dimension (faces and/or edges). Only some MeshIO subclasses support this! """ if isinstance(filename, Mesh): return filename if io == 'auto': if filename is None: output('filename or io must be specified!') raise ValueError else: io = MeshIO.any_from_filename(filename, prefix_dir=prefix_dir, file_format=file_format) output('reading mesh (%s)...' % io.filename) timer = Timer(start=True) trunk = io.get_filename_trunk() mesh = Mesh(trunk) mesh = io.read(mesh, omit_facets=omit_facets) output('...done in %.2f s' % timer.stop()) mesh._set_shape_info() return mesh
def __call__(self, volume=None, problem=None, data=None): problem = get_default(problem, self.problem) opts = self.app_options evp, dv_info = [data[ii] for ii in self.requires] output('computing eigenmomenta...') if opts.transform is not None: fun = problem.conf.get_function(opts.transform[0]) def wrap_transform(vec, shape): return fun(vec, shape, *opts.eig_vector_transform[1:]) else: wrap_transform = None timer = Timer(start=True) eigenmomenta = compute_eigenmomenta(self.expression, opts.var_name, problem, evp.eig_vectors, wrap_transform) output('...done in %.2f s' % timer.stop()) n_eigs = evp.eigs.shape[0] mag = norm_l2_along_axis(eigenmomenta) if opts.threshold_is_relative: tol = opts.threshold * mag.max() else: tol = opts.threshold valid = nm.where(mag < tol, False, True) mask = nm.where(valid == False)[0] eigenmomenta[mask, :] = 0.0 n_zeroed = mask.shape[0] output('%d of %d eigenmomenta zeroed (under %.2e)'\ % (n_zeroed, n_eigs, tol)) out = Struct(name='eigenmomenta', n_zeroed=n_zeroed, eigenmomenta=eigenmomenta, valid=valid, to_file_txt=None) return out
def check_tangent_matrix(conf, vec_x0, fun, fun_grad): """ Verify the correctness of the tangent matrix as computed by `fun_grad()` by comparing it with its finite difference approximation evaluated by repeatedly calling `fun()` with `vec_x0` items perturbed by a small delta. """ vec_x = vec_x0.copy() delta = conf.delta vec_r = fun(vec_x) # Update state. mtx_a0 = fun_grad(vec_x) mtx_a = mtx_a0.tocsc() mtx_d = mtx_a.copy() mtx_d.data[:] = 0.0 vec_dx = nm.zeros_like(vec_r) for ic in range(vec_dx.shape[0]): vec_dx[ic] = delta xx = vec_x.copy() - vec_dx vec_r1 = fun(xx) vec_dx[ic] = -delta xx = vec_x.copy() - vec_dx vec_r2 = fun(xx) vec_dx[ic] = 0.0; vec = 0.5 * (vec_r2 - vec_r1) / delta ir = mtx_a.indices[mtx_a.indptr[ic]:mtx_a.indptr[ic+1]] mtx_d.data[mtx_a.indptr[ic]:mtx_a.indptr[ic+1]] = vec[ir] vec_r = fun(vec_x) # Restore. timer = Timer(start=True) output(mtx_a, '.. analytical') output(mtx_d, '.. difference') import sfepy.base.plotutils as plu plu.plot_matrix_diff(mtx_d, mtx_a, delta, ['difference', 'analytical'], conf.check) return timer.stop()
def partition_mesh(mesh, n_parts, use_metis=True, verbose=False): """ Partition the mesh cells into `n_parts` subdomains, using metis, if available. """ output('partitioning mesh into %d subdomains...' % n_parts, verbose=verbose) timer = Timer(start=True) if use_metis: try: from pymetis import part_graph except ImportError: output('pymetis is not available, using naive partitioning!') part_graph = None if use_metis and (part_graph is not None): cmesh = mesh.cmesh cmesh.setup_connectivity(cmesh.dim, cmesh.dim) graph = cmesh.get_conn(cmesh.dim, cmesh.dim) cuts, cell_tasks = part_graph(n_parts, xadj=graph.offsets.astype(int), adjncy=graph.indices.astype(int)) cell_tasks = nm.array(cell_tasks, dtype=nm.int32) else: ii = nm.arange(n_parts) n_cell_parts = mesh.n_el // n_parts + ((mesh.n_el % n_parts) > ii) output('cell counts:', n_cell_parts, verbose=verbose) assert_(sum(n_cell_parts) == mesh.n_el) assert_(nm.all(n_cell_parts > 0)) offs = nm.cumsum(nm.r_[0, n_cell_parts]) cell_tasks = nm.digitize(nm.arange(offs[-1]), offs) - 1 output('...done in', timer.stop(), verbose=verbose) return cell_tasks
def init_solvers(self, problem): """ Setup solvers. Use local options if these are defined, otherwise use the global ones. For linear problems, assemble the matrix and try to presolve the linear system. """ if hasattr(self, 'solvers'): opts = self.solvers else: opts = problem.conf.options problem.set_conf_solvers(problem.conf.solvers, opts) problem.init_solvers() if self.is_linear: output('linear problem, trying to presolve...') timer = Timer(start=True) ev = problem.get_evaluator() state = problem.create_state() try: mtx_a = ev.eval_tangent_matrix(state(), is_full=True) except ValueError: output('matrix evaluation failed, giving up...') raise problem.set_linear(True) problem.try_presolve(mtx_a) output('...done in %.2f s' % timer.stop()) else: problem.set_linear(False)
def __call__(self, x0, conf=None, obj_fun=None, obj_fun_grad=None, status=None, obj_args=None): import inspect if conf is not None: self.set_method(conf) else: conf = self.conf obj_fun = get_default(obj_fun, self.obj_fun) obj_fun_grad = get_default(obj_fun_grad, self.obj_fun_grad) status = get_default(status, self.status) obj_args = get_default(obj_args, self.obj_args) timer = Timer(start=True) kwargs = {self._i_max_name[conf.method]: conf.i_max, 'args': obj_args} if conf.method in self._has_grad: kwargs['fprime'] = obj_fun_grad if 'disp' in inspect.getargspec(self.solver)[0]: kwargs['disp'] = conf.verbose kwargs.update(self.build_solver_kwargs(conf)) out = self.solver(obj_fun, x0, **kwargs) if status is not None: status['time_stats'] = timer.stop() return out
def evaluate_at(self, coors, source_vals, mode='val', strategy='general', close_limit=0.1, get_cells_fun=None, cache=None, ret_cells=False, ret_status=False, ret_ref_coors=False, verbose=False): """ Evaluate source DOF values corresponding to the field in the given coordinates using the field interpolation. Parameters ---------- coors : array, shape ``(n_coor, dim)`` The coordinates the source values should be interpolated into. source_vals : array, shape ``(n_nod, n_components)`` The source DOF values corresponding to the field. mode : {'val', 'grad'}, optional The evaluation mode: the field value (default) or the field value gradient. strategy : {'general', 'convex'}, optional The strategy for finding the elements that contain the coordinates. For convex meshes, the 'convex' strategy might be faster than the 'general' one. close_limit : float, optional The maximum limit distance of a point from the closest element allowed for extrapolation. get_cells_fun : callable, optional If given, a function with signature ``get_cells_fun(coors, cmesh, **kwargs)`` returning cells and offsets that potentially contain points with the coordinates `coors`. Applicable only when `strategy` is 'general'. When not given, :func:`get_potential_cells() <sfepy.discrete.common.global_interp.get_potential_cells>` is used. cache : Struct, optional To speed up a sequence of evaluations, the field mesh and other data can be cached. Optionally, the cache can also contain the reference element coordinates as `cache.ref_coors`, `cache.cells` and `cache.status`, if the evaluation occurs in the same coordinates repeatedly. In that case the mesh related data are ignored. See :func:`Field.get_evaluate_cache() <sfepy.discrete.fem.fields_base.FEField.get_evaluate_cache()>`. ret_ref_coors : bool, optional If True, return also the found reference element coordinates. ret_status : bool, optional If True, return also the enclosing cell status for each point. ret_cells : bool, optional If True, return also the cell indices the coordinates are in. verbose : bool If False, reduce verbosity. Returns ------- vals : array The interpolated values with shape ``(n_coor, n_components)`` or gradients with shape ``(n_coor, n_components, dim)`` according to the `mode`. If `ret_status` is False, the values where the status is greater than one are set to ``numpy.nan``. ref_coors : array The found reference element coordinates, if `ret_ref_coors` is True. cells : array The cell indices, if `ret_ref_coors` or `ret_cells` or `ret_status` are True. status : array The status, if `ret_ref_coors` or `ret_status` are True, with the following meaning: 0 is success, 1 is extrapolation within `close_limit`, 2 is extrapolation outside `close_limit`, 3 is failure, 4 is failure due to non-convergence of the Newton iteration in tensor product cells. If close_limit is 0, then for the 'general' strategy the status 5 indicates points outside of the field domain that had no potential cells. """ from sfepy.discrete.common.global_interp import get_ref_coors from sfepy.discrete.common.extmods.crefcoors import evaluate_in_rc from sfepy.base.base import complex_types output('evaluating in %d points...' % coors.shape[0], verbose=verbose) ref_coors, cells, status = get_ref_coors(self, coors, strategy=strategy, close_limit=close_limit, get_cells_fun=get_cells_fun, cache=cache, verbose=verbose) timer = Timer(start=True) # Interpolate to the reference coordinates. source_dtype = nm.float64 if source_vals.dtype in complex_types\ else source_vals.dtype if mode == 'val': vals = nm.empty((coors.shape[0], source_vals.shape[1], 1), dtype=source_dtype) cmode = 0 elif mode == 'grad': vals = nm.empty( (coors.shape[0], source_vals.shape[1], coors.shape[1]), dtype=source_dtype) cmode = 1 ctx = self.create_basis_context() if source_vals.dtype in complex_types: valsi = vals.copy() evaluate_in_rc(vals, ref_coors, cells, status, nm.ascontiguousarray(source_vals.real), self.get_econn('volume', self.region), cmode, ctx) evaluate_in_rc(valsi, ref_coors, cells, status, nm.ascontiguousarray(source_vals.imag), self.get_econn('volume', self.region), cmode, ctx) vals = vals + valsi * 1j else: evaluate_in_rc(vals, ref_coors, cells, status, source_vals, self.get_econn('volume', self.region), cmode, ctx) output('interpolation: %f s' % timer.stop(), verbose=verbose) output('...done', verbose=verbose) if mode == 'val': vals.shape = (coors.shape[0], source_vals.shape[1]) if not ret_status: ii = nm.where(status > 1)[0] vals[ii] = nm.nan if ret_ref_coors: return vals, ref_coors, cells, status elif ret_status: return vals, cells, status elif ret_cells: return vals, cells else: return vals
def recover_micro_hook_eps(micro_filename, region, eval_var, nodal_values, const_values, eps0, recovery_file_tag='', define_args=None, verbose=False): # Create a micro-problem instance. required, other = get_standard_keywords() required.remove('equations') conf = ProblemConf.from_file(micro_filename, required, other, verbose=False, define_args=define_args) coefs_filename = conf.options.get('coefs_filename', 'coefs') output_dir = conf.options.get('output_dir', '.') coefs_filename = op.join(output_dir, coefs_filename) + '.h5' # Coefficients and correctors coefs = Coefficients.from_file_hdf5(coefs_filename) corrs = get_correctors_from_file_hdf5(dump_names=coefs.save_names) recovery_hook = conf.options.get('recovery_hook', None) if recovery_hook is not None: recovery_hook = conf.get_function(recovery_hook) pb = Problem.from_conf(conf, init_equations=False, init_solvers=False) # Get tiling of a given region rcoors = region.domain.mesh.coors[region.get_entities(0), :] rcmin = nm.min(rcoors, axis=0) rcmax = nm.max(rcoors, axis=0) nn = nm.round((rcmax - rcmin) / eps0) if nm.prod(nn) == 0: output('inconsistency in recovery region and microstructure size!') return cs = [] for ii, n in enumerate(nn): cs.append(nm.arange(n) * eps0 + rcmin[ii]) x0 = nm.empty((int(nm.prod(nn)), nn.shape[0]), dtype=nm.float64) for ii, icoor in enumerate(nm.meshgrid(*cs, indexing='ij')): x0[:, ii] = icoor.flatten() mesh = pb.domain.mesh coors, conn, outs, ndoffset = [], [], [], 0 # Recover region mic_coors = (mesh.coors - mesh.get_bounding_box()[0, :]) * eps0 evfield = eval_var.field output('recovering microsctructures...') timer = Timer(start=True) output_fun = output.output_function output_level = output.level for ii, c0 in enumerate(x0): local_macro = {'eps0': eps0} local_coors = mic_coors + c0 # Inside recovery region? v = nm.ones((evfield.region.entities[0].shape[0], 1)) v[evfield.vertex_remap[region.entities[0]]] = 0 no = nm.sum(v) aux = evfield.evaluate_at(local_coors, v) if no > 0 and (nm.sum(aux) / no) > 1e-3: continue output.level = output_level output('micro: %d' % ii) for k, v in six.iteritems(nodal_values): local_macro[k] = evfield.evaluate_at(local_coors, v) for k, v in six.iteritems(const_values): local_macro[k] = v output.set_output(quiet=not(verbose)) outs.append(recovery_hook(pb, corrs, local_macro)) output.output_function = output_fun coors.append(local_coors) conn.append(mesh.get_conn(mesh.descs[0]) + ndoffset) ndoffset += mesh.n_nod output('...done in %.2f s' % timer.stop()) # Collect output variables outvars = {} for k, v in six.iteritems(outs[0]): if v.var_name in outvars: outvars[v.var_name].append(k) else: outvars[v.var_name] = [k] # Split output by variables/regions pvs = pb.create_variables(outvars.keys()) outregs = {k: pvs[k].field.region.get_entities(-1) for k in outvars.keys()} nrve = len(coors) coors = nm.vstack(coors) ngroups = nm.tile(mesh.cmesh.vertex_groups.squeeze(), (nrve,)) conn = nm.vstack(conn) cgroups = nm.tile(mesh.cmesh.cell_groups.squeeze(), (nrve,)) # Get region mesh and data for k, cidxs in six.iteritems(outregs): gcidxs = nm.hstack([cidxs + mesh.n_el * ii for ii in range(nrve)]) rconn = conn[gcidxs] remap = -nm.ones((coors.shape[0],), dtype=nm.int32) remap[rconn] = 1 vidxs = nm.where(remap > 0)[0] remap[vidxs] = nm.arange(len(vidxs)) rconn = remap[rconn] rcoors = coors[vidxs, :] out = {} for ifield in outvars[k]: data = [outs[ii][ifield].data for ii in range(nrve)] out[ifield] = Struct(name='output_data', mode=outs[0][ifield].mode, dofs=None, var_name=k, data=nm.vstack(data)) micro_name = pb.get_output_name(extra='recovered%s_%s' % (recovery_file_tag, k)) filename = op.join(output_dir, op.basename(micro_name)) mesh_out = Mesh.from_data('recovery_%s' % k, rcoors, ngroups[vidxs], [rconn], [cgroups[gcidxs]], [mesh.descs[0]]) mesh_out.write(filename, io='auto', out=out)
def solve_problem(mesh_filename, options, comm): order_u = options.order_u order_p = options.order_p rank, size = comm.Get_rank(), comm.Get_size() output('rank', rank, 'of', size) stats = Struct() timer = Timer('solve_timer') timer.start() mesh = Mesh.from_file(mesh_filename) stats.t_read_mesh = timer.stop() timer.start() if rank == 0: cell_tasks = pl.partition_mesh(mesh, size, use_metis=options.metis, verbose=True) else: cell_tasks = None stats.t_partition_mesh = timer.stop() output('creating global domain and fields...') timer.start() domain = FEDomain('domain', mesh) omega = domain.create_region('Omega', 'all') field1 = Field.from_args('fu', nm.float64, mesh.dim, omega, approx_order=order_u) field2 = Field.from_args('fp', nm.float64, 1, omega, approx_order=order_p) fields = [field1, field2] stats.t_create_global_fields = timer.stop() output('...done in', timer.dt) output('distributing fields...') timer.start() distribute = pl.distribute_fields_dofs lfds, gfds = distribute(fields, cell_tasks, is_overlap=True, use_expand_dofs=True, save_inter_regions=options.save_inter_regions, output_dir=options.output_dir, comm=comm, verbose=True) stats.t_distribute_fields_dofs = timer.stop() output('...done in', timer.dt) output('creating local problem...') timer.start() cells = lfds[0].cells omega_gi = Region.from_cells(cells, domain) omega_gi.finalize() omega_gi.update_shape() pb = create_local_problem(omega_gi, [order_u, order_p]) variables = pb.get_variables() state = State(variables) state.fill(0.0) state.apply_ebc() stats.t_create_local_problem = timer.stop() output('...done in', timer.dt) output('allocating global system...') timer.start() sizes, drange, pdofs = pl.setup_composite_dofs(lfds, fields, variables, verbose=True) pmtx, psol, prhs = pl.create_petsc_system(pb.mtx_a, sizes, pdofs, drange, is_overlap=True, comm=comm, verbose=True) stats.t_allocate_global_system = timer.stop() output('...done in', timer.dt) output('creating solver...') timer.start() conf = Struct(method='bcgsl', precond='jacobi', sub_precond='none', i_max=10000, eps_a=1e-50, eps_r=1e-6, eps_d=1e4, verbose=True) status = {} ls = PETScKrylovSolver(conf, comm=comm, mtx=pmtx, status=status) field_ranges = {} for ii, variable in enumerate(variables.iter_state(ordered=True)): field_ranges[variable.name] = lfds[ii].petsc_dofs_range ls.set_field_split(field_ranges, comm=comm) ev = PETScParallelEvaluator(pb, pdofs, drange, True, psol, comm, verbose=True) nls_status = {} conf = Struct(method='newtonls', i_max=5, eps_a=0, eps_r=1e-5, eps_s=0.0, verbose=True) nls = PETScNonlinearSolver(conf, pmtx=pmtx, prhs=prhs, comm=comm, fun=ev.eval_residual, fun_grad=ev.eval_tangent_matrix, lin_solver=ls, status=nls_status) stats.t_create_solver = timer.stop() output('...done in', timer.dt) output('solving...') timer.start() state = pb.create_state() state.apply_ebc() ev.psol_i[...] = state() ev.gather(psol, ev.psol_i) psol = nls(psol) ev.scatter(ev.psol_i, psol) sol0_i = ev.psol_i[...] stats.t_solve = timer.stop() output('...done in', timer.dt) output('saving solution...') timer.start() state.set_full(sol0_i) out = state.create_output_dict() filename = os.path.join(options.output_dir, 'sol_%02d.h5' % comm.rank) pb.domain.mesh.write(filename, io='auto', out=out) gather_to_zero = pl.create_gather_to_zero(psol) psol_full = gather_to_zero(psol) if comm.rank == 0: sol = psol_full[...].copy() u = FieldVariable('u', 'parameter', field1, primary_var_name='(set-to-None)') remap = gfds[0].id_map ug = sol[remap] p = FieldVariable('p', 'parameter', field2, primary_var_name='(set-to-None)') remap = gfds[1].id_map pg = sol[remap] if (((order_u == 1) and (order_p == 1)) or (options.linearization == 'strip')): out = u.create_output(ug) out.update(p.create_output(pg)) filename = os.path.join(options.output_dir, 'sol.h5') mesh.write(filename, io='auto', out=out) else: out = u.create_output(ug, linearization=Struct(kind='adaptive', min_level=0, max_level=order_u, eps=1e-3)) filename = os.path.join(options.output_dir, 'sol_u.h5') out['u'].mesh.write(filename, io='auto', out=out) out = p.create_output(pg, linearization=Struct(kind='adaptive', min_level=0, max_level=order_p, eps=1e-3)) filename = os.path.join(options.output_dir, 'sol_p.h5') out['p'].mesh.write(filename, io='auto', out=out) stats.t_save_solution = timer.stop() output('...done in', timer.dt) stats.t_total = timer.total stats.n_dof = sizes[1] stats.n_dof_local = sizes[0] stats.n_cell = omega.shape.n_cell stats.n_cell_local = omega_gi.shape.n_cell return stats
def __call__(self, vec_x0, conf=None, fun=None, fun_grad=None, lin_solver=None, iter_hook=None, status=None): """ Nonlinear system solver call. Solves a nonlinear system :math:`f(x) = 0` using the Newton method with backtracking line-search, starting with an initial guess :math:`x^0`. Parameters ---------- vec_x0 : array The initial guess vector :math:`x_0`. conf : Struct instance, optional The solver configuration parameters, fun : function, optional The function :math:`f(x)` whose zero is sought - the residual. fun_grad : function, optional The gradient of :math:`f(x)` - the tangent matrix. lin_solver : LinearSolver instance, optional The linear solver for each nonlinear iteration. iter_hook : function, optional User-supplied function to call before each iteration. status : dict-like, optional The user-supplied object to hold convergence statistics. Notes ----- * The optional parameters except `iter_hook` and `status` need to be given either here or upon `Newton` construction. * Setting `conf.is_linear == True` means a pre-assembled and possibly pre-solved matrix. This is mostly useful for linear time-dependent problems. """ conf = get_default(conf, self.conf) fun = get_default(fun, self.fun) fun_grad = get_default(fun_grad, self.fun_grad) lin_solver = get_default(lin_solver, self.lin_solver) iter_hook = get_default(iter_hook, self.iter_hook) status = get_default(status, self.status) ls_eps_a, ls_eps_r = lin_solver.get_tolerance() eps_a = get_default(ls_eps_a, 1.0) eps_r = get_default(ls_eps_r, 1.0) lin_red = conf.eps_a * conf.lin_red timer = Timer() time_stats_keys = ['residual', 'matrix', 'solve'] time_stats = {key : 0.0 for key in time_stats_keys} vec_x = vec_x0.copy() vec_x_last = vec_x0.copy() vec_dx = None if self.log is not None: self.log.plot_vlines(color='r', linewidth=1.0) err = err0 = -1.0 err_last = -1.0 it = 0 ls_status = {} ls_n_iter = 0 while 1: if iter_hook is not None: iter_hook(self, vec_x, it, err, err0) ls = 1.0 vec_dx0 = vec_dx; while 1: timer.start() try: vec_r = fun(vec_x) except ValueError: if (it == 0) or (ls < conf.ls_min): output('giving up!') raise else: ok = False else: ok = True time_stats['residual'] = timer.stop() if ok: try: err = nla.norm(vec_r) except: output('infs or nans in the residual:', vec_r) output(nm.isfinite(vec_r).all()) debug() if self.log is not None: self.log(err, it) if it == 0: err0 = err; break if err < (err_last * conf.ls_on): break red = conf.ls_red; output('linesearch: iter %d, (%.5e < %.5e) (new ls: %e)' % (it, err, err_last * conf.ls_on, red * ls)) else: # Failure. if conf.give_up_warp: output('giving up!') break red = conf.ls_red_warp; output('residual computation failed for iter %d' ' (new ls: %e)!' % (it, red * ls)) if ls < conf.ls_min: output('linesearch failed, continuing anyway') break ls *= red; vec_dx = ls * vec_dx0; vec_x = vec_x_last.copy() - vec_dx # End residual loop. if self.log is not None: self.log.plot_vlines([1], color='g', linewidth=0.5) err_last = err; vec_x_last = vec_x.copy() condition = conv_test(conf, it, err, err0) if condition >= 0: break if (not ok) and conf.give_up_warp: condition = 2 break timer.start() if not conf.is_linear: mtx_a = fun_grad(vec_x) else: mtx_a = fun_grad('linear') time_stats['matrix'] = timer.stop() if conf.check: timer.start() wt = check_tangent_matrix(conf, vec_x, fun, fun_grad) time_stats['check'] = timer.stop() - wt if conf.lin_precision is not None: if ls_eps_a is not None: eps_a = max(err * conf.lin_precision, ls_eps_a) elif ls_eps_r is not None: eps_r = max(conf.lin_precision, ls_eps_r) lin_red = max(eps_a, err * eps_r) if conf.verbose: output('solving linear system...') timer.start() vec_dx = lin_solver(vec_r, x0=vec_x, eps_a=eps_a, eps_r=eps_r, mtx=mtx_a, status=ls_status) ls_n_iter += ls_status['n_iter'] time_stats['solve'] = timer.stop() if conf.verbose: output('...done') for key in time_stats_keys: output('%10s: %7.2f [s]' % (key, time_stats[key])) vec_e = mtx_a * vec_dx - vec_r lerr = nla.norm(vec_e) if lerr > lin_red: output('warning: linear system solution precision is lower') output('then the value set in solver options! (err = %e < %e)' % (lerr, lin_red)) vec_x -= vec_dx it += 1 if status is not None: status['time_stats'] = time_stats status['err0'] = err0 status['err'] = err status['n_iter'] = it status['ls_n_iter'] = ls_n_iter if ls_n_iter >= 0 else -1 status['condition'] = condition if conf.log.plot is not None: if self.log is not None: self.log(save_figure=conf.log.plot) return vec_x
def __call__(self, vec_x0, conf=None, fun=None, fun_grad=None, lin_solver=None, iter_hook=None, status=None, pmtx=None, prhs=None, comm=None): conf = self.conf fun = get_default(fun, self.fun) fun_grad = get_default(fun_grad, self.fun_grad) lin_solver = get_default(lin_solver, self.lin_solver) iter_hook = get_default(iter_hook, self.iter_hook) status = get_default(status, self.status) pmtx = get_default(pmtx, self.pmtx) prhs = get_default(prhs, self.prhs) comm = get_default(comm, self.comm) timer = Timer(start=True) if isinstance(vec_x0, self.petsc.Vec): psol = vec_x0 else: psol = pmtx.getVecLeft() psol[...] = vec_x0 snes = self.petsc.SNES() snes.create(comm) snes.setType(conf.method) ksp = lin_solver.create_ksp() snes.setKSP(ksp) ls_conf = lin_solver.conf ksp.setTolerances(atol=ls_conf.eps_a, rtol=ls_conf.eps_r, divtol=ls_conf.eps_d, max_it=ls_conf.i_max) snes.setFunction(fun, prhs) snes.setJacobian(fun_grad, pmtx) snes.setTolerances(atol=conf.eps_a, rtol=conf.eps_r, stol=conf.eps_s, max_it=conf.i_max) snes.setMaxFunctionEvaluations(conf.if_max) snes.setFromOptions() fun(snes, psol, prhs) err0 = prhs.norm() snes.solve(prhs.duplicate(), psol) if status is not None: status['time_stats'] = timer.stop() if snes.reason in self.converged_reasons: reason = 'snes: %s' % self.converged_reasons[snes.reason] else: reason = 'ksp: %s' % self.ksp_converged_reasons[snes.reason] output('%s(%s): %d iterations in the last step' % (ksp.getType(), ksp.getPC().getType(), ksp.getIterationNumber()), verbose=conf.verbose) output('%s convergence: %s (%s, %d iterations, %d function evaluations)' % (snes.getType(), snes.reason, reason, snes.getIterationNumber(), snes.getFunctionEvaluations()), verbose=conf.verbose) converged = snes.reason >= 0 if not converged: # PETSc does not update the solution if KSP have not converged. dpsol = snes.getSolutionUpdate() psol -= dpsol fun(snes, psol, prhs) err = prhs.norm() else: try: err = snes.getFunctionNorm() except AttributeError: fun(snes, psol, prhs) err = prhs.norm() if status is not None: status['err0'] = err0 status['err'] = err status['n_iter'] = snes.getIterationNumber() status['ls_n_iter'] = snes.getLinearSolveIterations() status['condition'] = 0 if converged else -1 if isinstance(vec_x0, self.petsc.Vec): sol = psol else: sol = psol[...].copy() return sol
def __call__(self, vec_x0, conf=None, fun=None, fun_grad=None, lin_solver=None, status=None, problem=None): """ Oseen solver is problem-specific - it requires a Problem instance. """ conf = get_default(conf, self.conf) fun = get_default(fun, self.fun) fun_grad = get_default(fun_grad, self.fun_grad) lin_solver = get_default(lin_solver, self.lin_solver) status = get_default(status, self.status) problem = get_default(problem, conf.problem, '`problem` parameter needs to be set!') timer = Timer() time_stats = {} stabil = problem.get_materials()[conf.stabil_mat] ns, ii = stabil.function.function.get_maps() variables = problem.get_variables() update_var = variables.set_from_state make_full_vec = variables.make_full_vec output('problem size:') output(' velocity: %s' % ii['us']) output(' pressure: %s' % ii['ps']) vec_x = vec_x0.copy() vec_x_prev = vec_x0.copy() vec_dx = None if self.log is not None: self.log.plot_vlines(color='r', linewidth=1.0) err0 = -1.0 it = 0 while 1: vec_x_prev_f = make_full_vec(vec_x_prev) update_var(ns['b'], vec_x_prev_f, ns['u']) vec_b = vec_x_prev_f[ii['u']] b_norm = nla.norm(vec_b, nm.inf) output('|b|_max: %.12e' % b_norm) vec_x_f = make_full_vec(vec_x) vec_u = vec_x_f[ii['u']] u_norm = nla.norm(vec_u, nm.inf) output('|u|_max: %.2e' % u_norm) stabil.function.set_extra_args(b_norm=b_norm) stabil.time_update(None, problem.equations, mode='force', problem=problem) max_pars = stabil.reduce_on_datas(lambda a, b: max(a, b.max())) output('stabilization parameters:') output(' gamma: %.12e' % max_pars[ns['gamma']]) output(' max(delta): %.12e' % max_pars[ns['delta']]) output(' max(tau): %.12e' % max_pars[ns['tau']]) if (not are_close(b_norm, 1.0)) and conf.adimensionalize: adimensionalize = True else: adimensionalize = False timer.start() try: vec_r = fun(vec_x) except ValueError: ok = False else: ok = True time_stats['residual'] = timer.stop() if ok: err = nla.norm(vec_r) if it == 0: err0 = err else: err += nla.norm(vec_dx) else: # Failure. output('residual computation failed for iter %d!' % it) raise RuntimeError('giving up...') if self.log is not None: self.log(err, it, max_pars[ns['gamma']], max_pars[ns['delta']], max_pars[ns['tau']]) condition = conv_test(conf, it, err, err0) if condition >= 0: break if adimensionalize: output('adimensionalizing') ## mat.viscosity = viscosity / b_norm ## vec_r[indx_us] /= b_norm timer.start() try: mtx_a = fun_grad(vec_x) except ValueError: ok = False else: ok = True time_stats['matrix'] = timer.stop() if not ok: raise RuntimeError('giving up...') timer.start() vec_dx = lin_solver(vec_r, x0=vec_x, mtx=mtx_a) time_stats['solve'] = timer.stop() vec_e = mtx_a * vec_dx - vec_r lerr = nla.norm(vec_e) if lerr > (conf.eps_a * conf.lin_red): output('linear system not solved! (err = %e)' % lerr) if adimensionalize: output('restoring pressure...') ## vec_dx[indx_ps] *= b_norm dx_norm = nla.norm(vec_dx) output('||dx||: %.2e' % dx_norm) for kv in six.iteritems(time_stats): output('%10s: %7.2f [s]' % kv) vec_x_prev = vec_x.copy() vec_x -= vec_dx it += 1 if conf.check_navier_stokes_residual: t1 = '+ dw_div_grad.%s.%s(%s.viscosity, %s, %s)' \ % (ns['i2'], ns['omega'], ns['fluid'], ns['v'], ns['u']) # t2 = '+ dw_lin_convect.%s(%s, %s, %s)' % (ns['omega'], # ns['v'], b_name, ns['u']) t2 = '+ dw_convect.%s.%s(%s, %s)' % (ns['i2'], ns['omega'], ns['v'], ns['u']) t3 = '- dw_stokes.%s.%s(%s, %s)' % (ns['i1'], ns['omega'], ns['v'], ns['p']) t4 = 'dw_stokes.%s.%s(%s, %s)' % (ns['i1'], ns['omega'], ns['u'], ns['q']) equations = { 'balance': ' '.join((t1, t2, t3)), 'incompressibility': t4, } problem.set_equations(equations) try: vec_rns0 = fun(vec_x0) vec_rns = fun(vec_x) except ValueError: ok = False else: ok = True if not ok: output('Navier-Stokes residual computation failed!') err_ns = err_ns0 = None else: err_ns0 = nla.norm(vec_rns0) err_ns = nla.norm(vec_rns) output('Navier-Stokes residual0: %.8e' % err_ns0) output('Navier-Stokes residual : %.8e' % err_ns) output('b - u: %.8e' % nla.norm(vec_b - vec_u)) output(condition) else: err_ns = None if status is not None: status['time_stats'] = time_stats status['err0'] = err0 status['err'] = err status['err_ns'] = err_ns status['condition'] = condition if conf.log.plot is not None: if self.log is not None: self.log(save_figure=conf.log.plot) return vec_x
def get_ref_coors_convex(field, coors, close_limit=0.1, cache=None, verbose=False): """ Get reference element coordinates and elements corresponding to given physical coordinates. Parameters ---------- field : Field instance The field defining the approximation. coors : array The physical coordinates. close_limit : float, optional The maximum limit distance of a point from the closest element allowed for extrapolation. cache : Struct, optional To speed up a sequence of evaluations, the field mesh and other data can be cached. Optionally, the cache can also contain the reference element coordinates as `cache.ref_coors`, `cache.cells` and `cache.status`, if the evaluation occurs in the same coordinates repeatedly. In that case the mesh related data are ignored. verbose : bool If False, reduce verbosity. Returns ------- ref_coors : array The reference coordinates. cells : array The cell indices corresponding to the reference coordinates. status : array The status: 0 is success, 1 is extrapolation within `close_limit`, 2 is extrapolation outside `close_limit`, 3 is failure, 4 is failure due to non-convergence of the Newton iteration in tensor product cells. Notes ----- Outline of the algorithm for finding xi such that X(xi) = P: 1. make inverse connectivity - for each vertex have cells it is in. 2. find the closest vertex V. 3. choose initial cell: i0 = first from cells incident to V. 4. while not P in C_i, change C_i towards P, check if P in new C_i. """ timer = Timer() ref_coors = get_default_attr(cache, 'ref_coors', None) if ref_coors is None: extrapolate = close_limit > 0.0 ref_coors = nm.empty_like(coors) cells = nm.empty((coors.shape[0], ), dtype=nm.int32) status = nm.empty((coors.shape[0], ), dtype=nm.int32) cmesh = get_default_attr(cache, 'cmesh', None) if cmesh is None: timer.start() mesh = field.create_mesh(extra_nodes=False) cmesh = mesh.cmesh gels = create_geometry_elements() cmesh.set_local_entities(gels) cmesh.setup_entities() centroids = cmesh.get_centroids(cmesh.tdim) if field.gel.name != '3_8': normals0 = cmesh.get_facet_normals() normals1 = None else: normals0 = cmesh.get_facet_normals(0) normals1 = cmesh.get_facet_normals(1) output('cmesh setup: %f s' % timer.stop(), verbose=verbose) else: centroids = cache.centroids normals0 = cache.normals0 normals1 = cache.normals1 kdtree = get_default_attr(cache, 'kdtree', None) if kdtree is None: from scipy.spatial import cKDTree as KDTree timer.start() kdtree = KDTree(cmesh.coors) output('kdtree: %f s' % timer.stop(), verbose=verbose) timer.start() ics = kdtree.query(coors)[1] output('kdtree query: %f s' % timer.stop(), verbose=verbose) ics = nm.asarray(ics, dtype=nm.int32) coors = nm.ascontiguousarray(coors) ctx = field.create_basis_context() timer.start() crc.find_ref_coors_convex(ref_coors, cells, status, coors, cmesh, centroids, normals0, normals1, ics, extrapolate, 1e-15, close_limit, ctx) output('ref. coordinates: %f s' % timer.stop(), verbose=verbose) else: cells = cache.cells status = cache.status return ref_coors, cells, status
def get_ref_coors_general(field, coors, close_limit=0.1, get_cells_fun=None, cache=None, verbose=False): """ Get reference element coordinates and elements corresponding to given physical coordinates. Parameters ---------- field : Field instance The field defining the approximation. coors : array The physical coordinates. close_limit : float, optional The maximum limit distance of a point from the closest element allowed for extrapolation. get_cells_fun : callable, optional If given, a function with signature ``get_cells_fun(coors, cmesh, **kwargs)`` returning cells and offsets that potentially contain points with the coordinates `coors`. When not given, :func:`get_potential_cells()` is used. cache : Struct, optional To speed up a sequence of evaluations, the field mesh and other data can be cached. Optionally, the cache can also contain the reference element coordinates as `cache.ref_coors`, `cache.cells` and `cache.status`, if the evaluation occurs in the same coordinates repeatedly. In that case the mesh related data are ignored. verbose : bool If False, reduce verbosity. Returns ------- ref_coors : array The reference coordinates. cells : array The cell indices corresponding to the reference coordinates. status : array The status: 0 is success, 1 is extrapolation within `close_limit`, 2 is extrapolation outside `close_limit`, 3 is failure, 4 is failure due to non-convergence of the Newton iteration in tensor product cells. If close_limit is 0, then status 5 indicates points outside of the field domain that had no potential cells. """ timer = Timer() ref_coors = get_default_attr(cache, 'ref_coors', None) if ref_coors is None: extrapolate = close_limit > 0.0 get = get_potential_cells if get_cells_fun is None else get_cells_fun ref_coors = nm.empty_like(coors) cells = nm.empty((coors.shape[0], ), dtype=nm.int32) status = nm.empty((coors.shape[0], ), dtype=nm.int32) cmesh = get_default_attr(cache, 'cmesh', None) if cmesh is None: timer.start() mesh = field.create_mesh(extra_nodes=False) cmesh = mesh.cmesh if get_cells_fun is None: centroids = cmesh.get_centroids(cmesh.tdim) else: centroids = None output('cmesh setup: %f s' % timer.stop(), verbose=verbose) else: centroids = cache.centroids timer.start() potential_cells, offsets = get(coors, cmesh, centroids=centroids, extrapolate=extrapolate) output('potential cells: %f s' % timer.stop(), verbose=verbose) coors = nm.ascontiguousarray(coors) ctx = field.create_basis_context() eval_cmesh = get_default_attr(cache, 'eval_cmesh', None) if eval_cmesh is None: timer.start() mesh = field.create_eval_mesh() if mesh is None: eval_cmesh = cmesh else: eval_cmesh = mesh.cmesh output('eval_cmesh setup: %f s' % timer.stop(), verbose=verbose) timer.start() crc.find_ref_coors(ref_coors, cells, status, coors, eval_cmesh, potential_cells, offsets, extrapolate, 1e-15, close_limit, ctx) if extrapolate: assert_(nm.all(status < 5)) output('ref. coordinates: %f s' % timer.stop(), verbose=verbose) else: cells = cache.cells status = cache.status return ref_coors, cells, status
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 recover_micro_hook(micro_filename, region, macro, naming_scheme='step_iel', recovery_file_tag='', define_args=None, verbose=False): # Create a micro-problem instance. required, other = get_standard_keywords() required.remove('equations') conf = ProblemConf.from_file(micro_filename, required, other, verbose=False, define_args=define_args) coefs_filename = conf.options.get('coefs_filename', 'coefs') output_dir = conf.options.get('output_dir', '.') coefs_filename = op.join(output_dir, coefs_filename) + '.h5' # Coefficients and correctors coefs = Coefficients.from_file_hdf5(coefs_filename) corrs = get_correctors_from_file_hdf5(dump_names=coefs.save_names) recovery_hook = conf.options.get('recovery_hook', None) if recovery_hook is not None: recovery_hook = conf.get_function(recovery_hook) pb = Problem.from_conf(conf, init_equations=False, init_solvers=False) format = get_print_info(pb.domain.mesh.n_el, fill='0')[1] output('recovering microsctructures...') timer = Timer(start=True) output_fun = output.output_function output_level = output.level for ii, iel in enumerate(region.cells): output.level = output_level output('micro: %d (el=%d)' % (ii, iel)) local_macro = {} for k, v in six.iteritems(macro): local_macro[k] = v[ii, 0] output.set_output(quiet=not(verbose)) out = recovery_hook(pb, corrs, local_macro) output.output_function = output_fun if ii == 0: new_keys = [] new_data = {} new_idxs = [] for k in six.iterkeys(local_macro): if k not in macro: new_keys.append(k) new_data[k] = [] new_idxs.append(ii) for jj in new_keys: new_data[jj].append(local_macro[jj]) # save data if out is not None: suffix = format % iel micro_name = pb.get_output_name(extra='recovered_' + recovery_file_tag + suffix) filename = op.join(output_dir, op.basename(micro_name)) fpv = pb.conf.options.get('file_per_var', False) pb.save_state(filename, out=out, file_per_var=fpv) output('...done in %.2f s' % timer.stop()) for jj in new_keys: lout = new_data[jj] macro[jj] = nm.zeros((nm.max(new_idxs) + 1, 1) + lout[0].shape, dtype=lout[0].dtype) out = macro[jj] for kk, ii in enumerate(new_idxs): out[ii, 0] = lout[kk]
def create_matrix_graph(self, any_dof_conn=False, rdcs=None, cdcs=None, shape=None, active_only=True, verbose=True): """ Create tangent matrix graph, i.e. preallocate and initialize the sparse storage needed for the tangent matrix. Order of DOF connectivities is not important. 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. shape : tuple, optional The required shape, if it is different from the shape determined by the equations variables. This may be needed if additional row and column DOF connectivities are passed in. active_only : bool If True, the matrix graph has reduced size and is created with the reduced (active DOFs only) numbering. verbose : bool If False, reduce verbosity. Returns ------- matrix : csr_matrix The matrix graph in the form of a CSR matrix with preallocated structure and zero data. """ if not self.variables.has_virtuals(): output('no matrix (no test variables)!') return None shape = get_default(shape, self.variables.get_matrix_shape()) output('matrix shape:', shape, verbose=verbose) if nm.prod(shape) == 0: output('no matrix (zero size)!') return None rdcs, cdcs = self.get_graph_conns(any_dof_conn=any_dof_conn, rdcs=rdcs, cdcs=cdcs, active_only=active_only) if not len(rdcs): output('no matrix (empty dof connectivities)!') return None output('assembling matrix graph...', verbose=verbose) timer = Timer(start=True) nnz, prow, icol = create_mesh_graph(shape[0], shape[1], len(rdcs), rdcs, cdcs) output('...done in %.2f s' % timer.stop(), verbose=verbose) output('matrix structural nonzeros: %d (%.2e%% fill)' \ % (nnz, float(nnz) / nm.prod(shape)), verbose=verbose) data = nm.zeros((nnz, ), dtype=self.variables.dtype) matrix = sp.csr_matrix((data, icol, prow), shape) return matrix