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_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 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 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, 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_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 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 run_test(conf_name, options, ifile): from sfepy.base.ioutils import ensure_path ensure_path(op.join(options.out_dir, 'any')) if options.filter_none or options.raise_on_error: of = None elif options.filter_less: of = OutputFilter(['<<<', '>>>', '...', '!!!', '+++', '---']) elif options.filter_more: of = OutputFilter(['+++', '---']) else: of = OutputFilter(['<<<', '+++', '---']) print('<<< [%d] %s' % (ifile, conf_name)) orig_prefix = output.get_output_prefix() output.set_output_prefix('[%d] %s' % (ifile, orig_prefix)) _required, other = get_standard_keywords() required = ['Test'] num = 1 timer = Timer('tests') try: conf = ProblemConf.from_file(conf_name, required, _required + other) test = conf.funmod.Test.from_conf(conf, options) num = test.get_number() ok = True print('>>> test instance prepared (%d test(s))' % num) except KeyboardInterrupt: print('>>> interrupted') sys.exit(0) except: print('--- test instance creation failed') if options.raise_on_error: raise ok, n_fail, n_total = False, num, num if ok: try: timer.start() output.set_output_prefix(orig_prefix) ok, n_fail, n_total = test.run(debug=options.raise_on_error, ifile=ifile) output.set_output_prefix('[%d] %s' % (ifile, orig_prefix)) timer.stop() except KeyboardInterrupt: print('>>> interrupted') sys.exit(0) except Exception as e: print('>>> %s' % e.__class__) if options.raise_on_error: raise ok, n_fail, n_total = False, num, num if ok: print('>>> all passed in %.2f s' % timer.total) else: print('!!! %s test failed' % n_fail) if of is not None: of.stop() output.set_output_prefix(orig_prefix) return n_fail, n_total, timer.total
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 smooth_mesh(mesh, n_iter=4, lam=0.6307, mu=-0.6347, weights=None, bconstr=True, volume_corr=False): """ FE mesh smoothing. Based on: [1] Steven K. Boyd, Ralph Muller, Smooth surface meshing for automated finite element model generation from 3D image data, Journal of Biomechanics, Volume 39, Issue 7, 2006, Pages 1287-1295, ISSN 0021-9290, 10.1016/j.jbiomech.2005.03.006. (http://www.sciencedirect.com/science/article/pii/S0021929005001442) Parameters ---------- mesh : mesh FE mesh. n_iter : integer, optional Number of iteration steps. lam : float, optional Smoothing factor, see [1]. mu : float, optional Unshrinking factor, see [1]. weights : array, optional Edge weights, see [1]. bconstr: logical, optional Boundary constraints, if True only surface smoothing performed. volume_corr: logical, optional Correct volume after smoothing process. Returns ------- coors : array Coordinates of mesh nodes. """ def laplacian(coors, weights): n_nod = coors.shape[0] displ = (weights - sps.identity(n_nod)) * coors return displ def taubin(coors0, weights, lam, mu, n_iter): coors = coors0.copy() for ii in range(n_iter): displ = laplacian(coors, weights) if nm.mod(ii, 2) == 0: coors += lam * displ else: coors += mu * displ return coors def get_volume(el, nd): from sfepy.linalg.utils import dets_fast dim = nd.shape[1] nnd = el.shape[1] etype = '%d_%d' % (dim, nnd) if etype == '2_4' or etype == '3_8': el = elems_q2t(el) nel = el.shape[0] #bc = nm.zeros((dim, ), dtype=nm.double) mul = 1.0 / factorial(dim) if dim == 3: mul *= -1.0 mtx = nm.ones((nel, dim + 1, dim + 1), dtype=nm.double) mtx[:, :, :-1] = nd[el, :] vols = mul * dets_fast(mtx) vol = vols.sum() bc = nm.dot(vols, mtx.sum(1)[:, :-1] / nnd) bc /= vol return vol, bc from sfepy.base.timing import Timer output('smoothing...') timer = Timer(start=True) if weights is None: n_nod = mesh.n_nod domain = FEDomain('mesh', mesh) cmesh = domain.cmesh # initiate all vertices as inner - hierarchy = 2 node_group = nm.ones((n_nod, ), dtype=nm.int16) * 2 # boundary vertices - set hierarchy = 4 if bconstr: # get "vertices of surface" facets = cmesh.get_surface_facets() f_verts = cmesh.get_incident(0, facets, cmesh.dim - 1) node_group[f_verts] = 4 # generate costs matrix e_verts = cmesh.get_conn(1, 0).indices fc1, fc2 = e_verts[0::2], e_verts[1::2] idxs = nm.where(node_group[fc2] >= node_group[fc1]) rows1 = fc1[idxs] cols1 = fc2[idxs] idxs = nm.where(node_group[fc1] >= node_group[fc2]) rows2 = fc2[idxs] cols2 = fc1[idxs] crows = nm.concatenate((rows1, rows2)) ccols = nm.concatenate((cols1, cols2)) costs = sps.coo_matrix((nm.ones_like(crows), (crows, ccols)), shape=(n_nod, n_nod), dtype=nm.double) # generate weights matrix idxs = list(range(n_nod)) aux = sps.coo_matrix( (1.0 / nm.asarray(costs.sum(1)).squeeze(), (idxs, idxs)), shape=(n_nod, n_nod), dtype=nm.double) #aux.setdiag(1.0 / costs.sum(1)) weights = (aux.tocsc() * costs.tocsc()).tocsr() coors = taubin(mesh.coors, weights, lam, mu, n_iter) output('...done in %.2f s' % timer.stop()) if volume_corr: output('rescaling...') timer.start() volume0, bc = get_volume(mesh.conns[0], mesh.coors) volume, _ = get_volume(mesh.conns[0], coors) scale = volume0 / volume output('scale factor: %.2f' % scale) coors = (coors - bc) * scale + bc output('...done in %.2f s' % timer.stop()) return coors
def __call__(self, x0, conf=None, obj_fun=None, obj_fun_grad=None, status=None, obj_args=None): conf = get_default(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) if conf.output: globals()['output'] = conf.output output('entering optimization loop...') nc_of, tt_of, fn_of = wrap_function(obj_fun, obj_args) nc_ofg, tt_ofg, fn_ofg = wrap_function(obj_fun_grad, obj_args) timer = Timer() time_stats = {'of': tt_of, 'ofg': tt_ofg, 'check': []} ofg = None it = 0 xit = x0.copy() while 1: of = fn_of(xit) if it == 0: of0 = ofit0 = of_prev = of of_prev_prev = of + 5000.0 if ofg is None: ofg = fn_ofg(xit) if conf.check: timer.start() check_gradient(xit, ofg, fn_of, conf.delta, conf.check) time_stats['check'].append(timer.stop()) ofg_norm = nla.norm(ofg, conf.norm) ret = conv_test(conf, it, of, ofit0, ofg_norm) if ret >= 0: break ofit0 = of ## # Backtrack (on errors). alpha = conf.ls0 can_ls = True while 1: xit2 = xit - alpha * ofg aux = fn_of(xit2) if self.log is not None: self.log(of, ofg_norm, alpha, it) if aux is None: alpha *= conf.ls_red_warp can_ls = False output('warp: reducing step (%f)' % alpha) elif conf.ls and conf.ls_method == 'backtracking': if aux < of * conf.ls_on: break alpha *= conf.ls_red output('backtracking: reducing step (%f)' % alpha) else: of_prev_prev = of_prev of_prev = aux break if alpha < conf.ls_min: if aux is None: raise RuntimeError('giving up...') output('linesearch failed, continuing anyway') break # These values are modified by the line search, even if it fails of_prev_bak = of_prev of_prev_prev_bak = of_prev_prev if conf.ls and can_ls and conf.ls_method == 'full': output('full linesearch...') alpha, fc, gc, of_prev, of_prev_prev, ofg1 = \ linesearch.line_search(fn_of,fn_ofg,xit, -ofg,ofg,of_prev,of_prev_prev, c2=0.4) if alpha is None: # line search failed -- use different one. alpha, fc, gc, of_prev, of_prev_prev, ofg1 = \ sopt.line_search(fn_of,fn_ofg,xit, -ofg,ofg,of_prev_bak, of_prev_prev_bak) if alpha is None or alpha == 0: # This line search also failed to find a better # solution. ret = 3 break output(' -> alpha: %.8e' % alpha) else: if conf.ls_method == 'full': output('full linesearch off (%s and %s)' % (conf.ls, can_ls)) ofg1 = None if self.log is not None: self.log.plot_vlines(color='g', linewidth=0.5) xit = xit - alpha * ofg if ofg1 is None: ofg = None else: ofg = ofg1.copy() for key, val in six.iteritems(time_stats): if len(val): output('%10s: %7.2f [s]' % (key, val[-1])) it = it + 1 output('status: %d' % ret) output('initial value: %.8e' % of0) output('current value: %.8e' % of) output('iterations: %d' % it) output('function evaluations: %d in %.2f [s]' % (nc_of[0], nm.sum(time_stats['of']))) output('gradient evaluations: %d in %.2f [s]' % (nc_ofg[0], nm.sum(time_stats['ofg']))) if self.log is not None: self.log(of, ofg_norm, alpha, it) if conf.log.plot is not None: self.log(save_figure=conf.log.plot, finished=True) else: self.log(finished=True) if status is not None: status['log'] = self.log status['status'] = status status['of0'] = of0 status['of'] = of status['it'] = it status['nc_of'] = nc_of[0] status['nc_ofg'] = nc_ofg[0] status['time_stats'] = time_stats return xit
def __call__(self, vec_x0, conf=None, fun_smooth=None, fun_smooth_grad=None, fun_a=None, fun_a_grad=None, fun_b=None, fun_b_grad=None, lin_solver=None, status=None): conf = get_default(conf, self.conf) fun_smooth = get_default(fun_smooth, self.fun_smooth) fun_smooth_grad = get_default(fun_smooth_grad, self.fun_smooth_grad) fun_a = get_default(fun_a, self.fun_a) fun_a_grad = get_default(fun_a_grad, self.fun_a_grad) fun_b = get_default(fun_b, self.fun_b) fun_b_grad = get_default(fun_b_grad, self.fun_b_grad) lin_solver = get_default(lin_solver, self.lin_solver) status = get_default(status, self.status) timer = Timer() time_stats = {} 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) err0 = -1.0 err_last = -1.0 it = 0 step_mode = 'regular' r_last = None reuse_matrix = False while 1: ls = 1.0 vec_dx0 = vec_dx i_ls = 0 while 1: timer.start() try: vec_smooth_r = fun_smooth(vec_x) vec_a_r = fun_a(vec_x) vec_b_r = fun_b(vec_x) except ValueError: vec_smooth_r = vec_semismooth_r = None if (it == 0) or (ls < conf.ls_min): output('giving up!') raise else: ok = False else: if conf.semismooth: # Semi-smooth equation. vec_semismooth_r = ( nm.sqrt(vec_a_r**2.0 + vec_b_r**2.0) - (vec_a_r + vec_b_r)) else: # Non-smooth equation (brute force). vec_semismooth_r = nm.where(vec_a_r < vec_b_r, vec_a_r, vec_b_r) r_last = (vec_smooth_r, vec_a_r, vec_b_r, vec_semismooth_r) ok = True time_stats['residual'] = timer.stop() if ok: vec_r = nm.r_[vec_smooth_r, vec_semismooth_r] try: err = nla.norm(vec_r) except: output('infs or nans in the residual:', vec_semismooth_r) output(nm.isfinite(vec_semismooth_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): step_mode = 'regular' break else: output('%s step line search' % step_mode) red = conf.ls_red[step_mode] output('iter %d, (%.5e < %.5e) (new ls: %e)'\ % (it, err, err_last * conf.ls_on, red * ls)) else: # Failed to compute residual. red = conf.ls_red_warp output('residual computation failed for iter %d' ' (new ls: %e)!' % (it, red * ls)) if ls < conf.ls_min: if step_mode == 'regular': output('restore previous state') vec_x = vec_x_last.copy() (vec_smooth_r, vec_a_r, vec_b_r, vec_semismooth_r) = r_last err = err_last reuse_matrix = True step_mode = 'steepest_descent' else: output('linesearch failed, continuing anyway') break ls *= red vec_dx = ls * vec_dx0 vec_x = vec_x_last.copy() - vec_dx i_ls += 1 # End residual loop. output('%s step' % step_mode) if self.log is not None: self.log.plot_vlines([1], color=self._colors[step_mode], linewidth=0.5) err_last = err vec_x_last = vec_x.copy() condition = conv_test(conf, it, err, err0) if condition >= 0: break timer.start() if not reuse_matrix: mtx_jac = self.compute_jacobian(vec_x, fun_smooth_grad, fun_a_grad, fun_b_grad, vec_smooth_r, vec_a_r, vec_b_r) else: reuse_matrix = False time_stats['matrix'] = timer.stop() timer.start() if step_mode == 'regular': vec_dx = lin_solver(vec_r, mtx=mtx_jac) vec_e = mtx_jac * 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) output('switching to steepest descent step') step_mode = 'steepest_descent' vec_dx = mtx_jac.T * vec_r else: vec_dx = mtx_jac.T * vec_r time_stats['solve'] = timer.stop() for kv in six.iteritems(time_stats): output('%10s: %7.2f [s]' % kv) vec_x -= vec_dx it += 1 if status is not None: status['time_stats'] = time_stats status['err0'] = err0 status['err'] = err 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 solve_problem(mesh_filename, options, comm): order = options.order 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 field...') timer.start() domain = FEDomain('domain', mesh) omega = domain.create_region('Omega', 'all') field = Field.from_args('fu', nm.float64, 1, omega, approx_order=order) stats.t_create_global_fields = timer.stop() output('...done in', timer.dt) output('distributing field %s...' % field.name) timer.start() distribute = pl.distribute_fields_dofs lfds, gfds = distribute([field], cell_tasks, is_overlap=True, save_inter_regions=options.save_inter_regions, output_dir=options.output_dir, comm=comm, verbose=True) lfd = lfds[0] stats.t_distribute_fields_dofs = timer.stop() output('...done in', timer.dt) if rank == 0: dof_maps = gfds[0].dof_maps id_map = gfds[0].id_map if options.verify: verify_save_dof_maps(field, cell_tasks, dof_maps, id_map, options, verbose=True) if options.plot: ppd.plot_partitioning([None, None], field, cell_tasks, gfds[0], options.output_dir, size) output('creating local problem...') timer.start() omega_gi = Region.from_cells(lfd.cells, field.domain) omega_gi.finalize() omega_gi.update_shape() pb = create_local_problem(omega_gi, order) variables = pb.get_variables() eqs = pb.equations u_i = variables['u_i'] field_i = u_i.field stats.t_create_local_problem = timer.stop() output('...done in', timer.dt) if options.plot: ppd.plot_local_dofs([None, None], field, field_i, omega_gi, options.output_dir, rank) output('allocating global system...') timer.start() sizes, drange = pl.get_sizes(lfd.petsc_dofs_range, field.n_nod, 1) output('sizes:', sizes) output('drange:', drange) pdofs = pl.get_local_ordering(field_i, lfd.petsc_dofs_conn) output('pdofs:', pdofs) 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('evaluating local problem...') timer.start() state = State(variables) state.fill(0.0) state.apply_ebc() rhs_i = eqs.eval_residuals(state()) # This must be after pl.create_petsc_system() call! mtx_i = eqs.eval_tangent_matrices(state(), pb.mtx_a) stats.t_evaluate_local_problem = timer.stop() output('...done in', timer.dt) output('assembling global system...') timer.start() apply_ebc_to_matrix(mtx_i, u_i.eq_map.eq_ebc) pl.assemble_rhs_to_petsc(prhs, rhs_i, pdofs, drange, is_overlap=True, comm=comm, verbose=True) pl.assemble_mtx_to_petsc(pmtx, mtx_i, pdofs, drange, is_overlap=True, comm=comm, verbose=True) stats.t_assemble_global_system = timer.stop() output('...done in', timer.dt) output('creating solver...') timer.start() conf = Struct(method='cg', precond='gamg', sub_precond='none', i_max=10000, eps_a=1e-50, eps_r=1e-5, eps_d=1e4, verbose=True) status = {} ls = PETScKrylovSolver(conf, comm=comm, mtx=pmtx, status=status) stats.t_create_solver = timer.stop() output('...done in', timer.dt) output('solving...') timer.start() psol = ls(prhs, psol) psol_i = pl.create_local_petsc_vector(pdofs) gather, scatter = pl.create_gather_scatter(pdofs, psol_i, psol, comm=comm) scatter(psol_i, psol) sol0_i = state() - psol_i[...] psol_i[...] = sol0_i gather(psol, psol_i) stats.t_solve = timer.stop() output('...done in', timer.dt) output('saving solution...') timer.start() u_i.set_data(sol0_i) out = u_i.create_output() 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()[id_map] u = FieldVariable('u', 'parameter', field, primary_var_name='(set-to-None)') filename = os.path.join(options.output_dir, 'sol.h5') if (order == 1) or (options.linearization == 'strip'): out = u.create_output(sol) mesh.write(filename, io='auto', out=out) else: out = u.create_output(sol, linearization=Struct(kind='adaptive', min_level=0, max_level=order, eps=1e-3)) out['u'].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 if options.show: plt.show() return stats
def get_evaluate_cache(self, cache=None, share_geometry=False, verbose=False): """ Get the evaluate cache for :func:`Variable.evaluate_at() <sfepy.discrete.variables.Variable.evaluate_at()>`. Parameters ---------- cache : Struct instance, optional Optionally, use the provided instance to store the cache data. share_geometry : bool Set to True to indicate that all the evaluations will work on the same region. Certain data are then computed only for the first probe and cached. verbose : bool If False, reduce verbosity. Returns ------- cache : Struct instance The evaluate cache. """ try: from scipy.spatial import cKDTree as KDTree except ImportError: from scipy.spatial import KDTree from sfepy.discrete.fem.geometry_element import create_geometry_elements if cache is None: cache = Struct(name='evaluate_cache') timer = Timer(start=True) if (cache.get('cmesh', None) is None) or not share_geometry: mesh = self.create_mesh(extra_nodes=False) cache.cmesh = cmesh = mesh.cmesh gels = create_geometry_elements() cmesh.set_local_entities(gels) cmesh.setup_entities() cache.centroids = cmesh.get_centroids(cmesh.tdim) if self.gel.name != '3_8': cache.normals0 = cmesh.get_facet_normals() cache.normals1 = None else: cache.normals0 = cmesh.get_facet_normals(0) cache.normals1 = cmesh.get_facet_normals(1) output('cmesh setup: %f s' % timer.stop(), verbose=verbose) timer.start() if (cache.get('kdtree', None) is None) or not share_geometry: cache.kdtree = KDTree(cmesh.coors) output('kdtree: %f s' % timer.stop(), verbose=verbose) return cache