def solve_pressure_eigenproblem(self, mtx, eig_problem=None, n_eigs=0, check=False): """G = B*AI*BT or B*AI*BT+D""" def get_slice(n_eigs, nn): if n_eigs > 0: ii = slice(0, n_eigs) elif n_eigs < 0: ii = slice(nn + n_eigs, nn) else: ii = slice(0, 0) return ii eig_problem = get_default(eig_problem, self.eig_problem) n_eigs = get_default(n_eigs, self.n_eigs) check = get_default(check, self.check) mtx_c, mtx_b, action_aibt = mtx['C'], mtx['B'], mtx['action_aibt'] mtx_g = mtx_b * action_aibt.to_array() # mtx_b must be sparse! if eig_problem == 'B*AI*BT+D': mtx_g += mtx['D'].toarray() mtx['G'] = mtx_g output(mtx_c.shape, mtx_g.shape) eigs, mtx_q = eig(mtx_c.toarray(), mtx_g, method='eig.sgscipy') if check: ee = nm.diag(sc.dot(mtx_q.T * mtx_c, mtx_q)).squeeze() oo = nm.diag(sc.dot(sc.dot(mtx_q.T, mtx_g), mtx_q)).squeeze() try: assert_(nm.allclose(ee, eigs)) assert_(nm.allclose(oo, nm.ones_like(eigs))) except ValueError: debug() nn = mtx_c.shape[0] if isinstance(n_eigs, tuple): output('required number of eigenvalues: (%d, %d)' % n_eigs) if sum(n_eigs) < nn: ii0 = get_slice(n_eigs[0], nn) ii1 = get_slice(-n_eigs[1], nn) eigs = nm.concatenate((eigs[ii0], eigs[ii1])) mtx_q = nm.concatenate((mtx_q[:,ii0], mtx_q[:,ii1]), 1) else: output('required number of eigenvalues: %d' % n_eigs) if (n_eigs != 0) and (abs(n_eigs) < nn): ii = get_slice(n_eigs, nn) eigs = eigs[ii] mtx_q = mtx_q[:,ii] ## from sfepy.base.plotutils import pylab, iplot ## pylab.semilogy(eigs) ## pylab.figure(2) ## iplot(eigs) ## pylab.show() ## debug() out = Struct(eigs=eigs, mtx_q=mtx_q) return out
def __call__(self, problem=None, data=None): problem = get_default(problem, self.problem) opts = self.app_options problem.set_equations(self.equations) problem.select_bcs(ebc_names=self.ebcs, epbc_names=self.epbcs, lcbc_names=self.get('lcbcs', [])) problem.update_materials(problem.ts) self.init_solvers(problem) mtx_a, mtx_m, data = self.prepare_matrices(problem) output('computing resonance frequencies...') tt = [0] if isinstance(mtx_a, sc.sparse.spmatrix): mtx_a = mtx_a.toarray() if isinstance(mtx_m, sc.sparse.spmatrix): mtx_m = mtx_m.toarray() eigs, mtx_s_phi = eig(mtx_a, mtx_m, return_time=tt, method=opts.eigensolver) eigs[eigs<0.0] = 0.0 output('...done in %.2f s' % tt[0]) output('original eigenfrequencies:') output(eigs) opts = self.app_options epsilon2 = opts.scale_epsilon * opts.scale_epsilon eigs_rescaled = (opts.elasticity_contrast / epsilon2) * eigs output('rescaled eigenfrequencies:') output(eigs_rescaled) output('number of eigenfrequencies: %d' % eigs.shape[0]) try: assert_(nm.isfinite(eigs).all()) except ValueError: from sfepy.base.base import debug; debug() mtx_phi, eig_vectors = self.post_process(eigs, mtx_s_phi, data, problem) self.save(eigs, mtx_phi, problem) evp = Struct(name='evp', eigs=eigs, eigs_rescaled=eigs_rescaled, eig_vectors=eig_vectors) return evp
def main(): parser = OptionParser(usage=usage, version="%prog") parser.add_option( "-b", "--basis", metavar="name", action="store", dest="basis", default="lagrange", help=help["basis"] ) parser.add_option( "-n", "--max-order", metavar="order", type=int, action="store", dest="max_order", default=10, help=help["max_order"], ) parser.add_option( "-m", "--matrix", metavar="type", action="store", dest="matrix_type", default="laplace", help=help["matrix_type"], ) parser.add_option( "-g", "--geometry", metavar="name", action="store", dest="geometry", default="2_4", help=help["geometry"] ) options, args = parser.parse_args() dim, n_ep = int(options.geometry[0]), int(options.geometry[2]) output("reference element geometry:") output(" dimension: %d, vertices: %d" % (dim, n_ep)) n_c = {"laplace": 1, "elasticity": dim}[options.matrix_type] output("matrix type:", options.matrix_type) output("number of variable components:", n_c) output("polynomial space:", options.basis) output("max. order:", options.max_order) mesh = Mesh.from_file(data_dir + "/meshes/elements/%s_1.mesh" % options.geometry) domain = Domain("domain", mesh) omega = domain.create_region("Omega", "all") orders = nm.arange(1, options.max_order + 1, dtype=nm.int) conds = [] order_fix = 0 if options.geometry in ["2_4", "3_8"] else 1 for order in orders: output("order:", order, "...") field = Field.from_args( "fu", nm.float64, n_c, omega, approx_order=order, space="H1", poly_space_base=options.basis ) to = field.approx_order quad_order = 2 * (max(to - order_fix, 0)) output("quadrature order:", quad_order) integral = Integral("i", order=quad_order) qp, _ = integral.get_qp(options.geometry) output("number of quadrature points:", qp.shape[0]) u = FieldVariable("u", "unknown", field, n_c) v = FieldVariable("v", "test", field, n_c, primary_var_name="u") m = Material("m", lam=1.0, mu=1.0) if options.matrix_type == "laplace": term = Term.new("dw_laplace(m.mu, v, u)", integral, omega, m=m, v=v, u=u) n_zero = 1 else: assert_(options.matrix_type == "elasticity") term = Term.new("dw_lin_elastic_iso(m.lam, m.mu, v, u)", integral, omega, m=m, v=v, u=u) n_zero = (dim + 1) * dim / 2 term.setup() output("assembling...") tt = time.clock() mtx, iels = term.evaluate(mode="weak", diff_var="u") output("...done in %.2f s" % (time.clock() - tt)) mtx = mtx[0][0, 0] try: assert_(nm.max(nm.abs(mtx - mtx.T)) < 1e-10) except: from sfepy.base.base import debug debug() output("matrix shape:", mtx.shape) eigs = eig(mtx, method="eig.sgscipy", eigenvectors=False) eigs.sort() # Zero 'true' zeros. eigs[:n_zero] = 0.0 ii = nm.where(eigs < 0.0)[0] if len(ii): output("matrix is not positive semi-definite!") ii = nm.where(eigs[n_zero:] < 1e-12)[0] if len(ii): output("matrix has more than %d zero eigenvalues!" % n_zero) output("smallest eigs:\n", eigs[:10]) ii = nm.where(eigs > 0.0)[0] emin, emax = eigs[ii[[0, -1]]] output("min:", emin, "max:", emax) cond = emax / emin conds.append(cond) output("condition number:", cond) output("...done") plt.figure(1) plt.semilogy(orders, conds) plt.xticks(orders, orders) plt.xlabel("polynomial order") plt.ylabel("condition number") plt.grid() plt.figure(2) plt.loglog(orders, conds) plt.xticks(orders, orders) plt.xlabel("polynomial order") plt.ylabel("condition number") plt.grid() plt.show()
def __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) 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: tt = time.clock() 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['rezidual'] = time.clock() - tt 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 rezidual. red = conf.ls_red_warp; output('rezidual 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 tt = time.clock() 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'] = time.clock() - tt tt = time.clock() 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'] = time.clock() - tt 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 main(): parser = OptionParser(usage=usage, version='%prog') parser.add_option('-b', '--basis', metavar='name', action='store', dest='basis', default='lagrange', help=help['basis']) parser.add_option('-n', '--max-order', metavar='order', type=int, action='store', dest='max_order', default=10, help=help['max_order']) parser.add_option('-m', '--matrix', metavar='type', action='store', dest='matrix_type', default='laplace', help=help['matrix_type']) parser.add_option('-g', '--geometry', metavar='name', action='store', dest='geometry', default='2_4', help=help['geometry']) options, args = parser.parse_args() dim, n_ep = int(options.geometry[0]), int(options.geometry[2]) output('reference element geometry:') output(' dimension: %d, vertices: %d' % (dim, n_ep)) n_c = {'laplace' : 1, 'elasticity' : dim}[options.matrix_type] output('matrix type:', options.matrix_type) output('number of variable components:', n_c) output('polynomial space:', options.basis) output('max. order:', options.max_order) mesh = Mesh.from_file(data_dir + '/meshes/elements/%s_1.mesh' % options.geometry) domain = FEDomain('domain', mesh) omega = domain.create_region('Omega', 'all') orders = nm.arange(1, options.max_order + 1, dtype=nm.int) conds = [] order_fix = 0 if options.geometry in ['2_4', '3_8'] else 1 for order in orders: output('order:', order, '...') field = Field.from_args('fu', nm.float64, n_c, omega, approx_order=order, space='H1', poly_space_base=options.basis) to = field.approx_order quad_order = 2 * (max(to - order_fix, 0)) output('quadrature order:', quad_order) integral = Integral('i', order=quad_order) qp, _ = integral.get_qp(options.geometry) output('number of quadrature points:', qp.shape[0]) u = FieldVariable('u', 'unknown', field) v = FieldVariable('v', 'test', field, primary_var_name='u') m = Material('m', lam=1.0, mu=1.0) if options.matrix_type == 'laplace': term = Term.new('dw_laplace(m.mu, v, u)', integral, omega, m=m, v=v, u=u) n_zero = 1 else: assert_(options.matrix_type == 'elasticity') term = Term.new('dw_lin_elastic_iso(m.lam, m.mu, v, u)', integral, omega, m=m, v=v, u=u) n_zero = (dim + 1) * dim / 2 term.setup() output('assembling...') tt = time.clock() mtx, iels = term.evaluate(mode='weak', diff_var='u') output('...done in %.2f s' % (time.clock() - tt)) mtx = mtx[0][0, 0] try: assert_(nm.max(nm.abs(mtx - mtx.T)) < 1e-10) except: from sfepy.base.base import debug; debug() output('matrix shape:', mtx.shape) eigs = eig(mtx, method='eig.sgscipy', eigenvectors=False) eigs.sort() # Zero 'true' zeros. eigs[:n_zero] = 0.0 ii = nm.where(eigs < 0.0)[0] if len(ii): output('matrix is not positive semi-definite!') ii = nm.where(eigs[n_zero:] < 1e-12)[0] if len(ii): output('matrix has more than %d zero eigenvalues!' % n_zero) output('smallest eigs:\n', eigs[:10]) ii = nm.where(eigs > 0.0)[0] emin, emax = eigs[ii[[0, -1]]] output('min:', emin, 'max:', emax) cond = emax / emin conds.append(cond) output('condition number:', cond) output('...done') plt.figure(1) plt.semilogy(orders, conds) plt.xticks(orders, orders) plt.xlabel('polynomial order') plt.ylabel('condition number') plt.grid() plt.figure(2) plt.loglog(orders, conds) plt.xticks(orders, orders) plt.xlabel('polynomial order') plt.ylabel('condition number') plt.grid() plt.show()
def __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.problem == 'linear'` means a pre-assembled and possibly pre-solved matrix. This is mostly useful for linear time-dependent problems. """ import sfepy.base.plotutils as plu 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 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) err = err0 = -1.0 err_last = -1.0 it = 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: tt = time.clock() 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['rezidual'] = time.clock() - tt 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( 'rezidual 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 tt = time.clock() if conf.problem == 'nonlinear': mtx_a = fun_grad(vec_x) else: mtx_a = fun_grad( 'linear' ) time_stats['matrix'] = time.clock() - tt if conf.check: tt = time.clock() wt = check_tangent_matrix( conf, vec_x, fun, fun_grad ) time_stats['check'] = time.clock() - tt - 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...') tt = time.clock() vec_dx = lin_solver(vec_r, x0=vec_x, eps_a=eps_a, eps_r=eps_r, mtx=mtx_a) time_stats['solve'] = time.clock() - tt if conf.verbose: output('...done') for kv in time_stats.iteritems(): output( '%10s: %7.2f [s]' % kv ) vec_e = mtx_a * vec_dx - vec_r lerr = nla.norm( vec_e ) if lerr > lin_red: output('linear system not solved! (err = %e < %e)' % (lerr, lin_red)) vec_x -= vec_dx if conf.is_plot: plu.plt.ion() plu.plt.gcf().clear() plu.plt.subplot( 2, 2, 1 ) plu.plt.plot( vec_x_last ) plu.plt.ylabel( r'$x_{i-1}$' ) plu.plt.subplot( 2, 2, 2 ) plu.plt.plot( vec_r ) plu.plt.ylabel( r'$r$' ) plu.plt.subplot( 2, 2, 4 ) plu.plt.plot( vec_dx ) plu.plt.ylabel( r'$\_delta x$' ) plu.plt.subplot( 2, 2, 3 ) plu.plt.plot( vec_x ) plu.plt.ylabel( r'$x_i$' ) plu.plt.draw() plu.plt.ioff() pause() it += 1 if status is not None: status['time_stats'] = time_stats status['err0'] = err0 status['err'] = err status['n_iter'] = it 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): """ 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 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) 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: tt = time.clock() 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['rezidual'] = time.clock() - tt 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('rezidual 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 tt = time.clock() if not conf.is_linear: mtx_a = fun_grad(vec_x) else: mtx_a = fun_grad('linear') time_stats['matrix'] = time.clock() - tt if conf.check: tt = time.clock() wt = check_tangent_matrix(conf, vec_x, fun, fun_grad) time_stats['check'] = time.clock() - tt - 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...') tt = time.clock() 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'] = time.clock() - tt if conf.verbose: output('...done') for kv in six.iteritems(time_stats): output('%10s: %7.2f [s]' % kv) 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 get_graph_conns(self, any_dof_conn=False, rdcs=None, cdcs=None): """ Get DOF connectivities needed for creating tangent matrix graph. Parameters ---------- any_dof_conn : bool By default, only volume DOF connectivities are used, with the exception of trace surface DOF connectivities. If True, any kind of DOF connectivities is allowed. rdcs, cdcs : arrays, optional Additional row and column DOF connectivities, corresponding to the variables used in the equations. Returns ------- rdcs, cdcs : arrays The row and column DOF connectivities defining the matrix graph blocks. """ if rdcs is None: rdcs = [] cdcs = [] elif cdcs is None: cdcs = copy(rdcs) else: assert_(len(rdcs) == len(cdcs)) if rdcs is cdcs: # Make sure the lists are not the same object. rdcs = copy(rdcs) adcs = self.variables.adof_conns # Only volume dof connectivities are used, with the exception of trace # surface dof connectivities. shared = set() for key, ii, info in iter_dict_of_lists(self.conn_info, return_keys=True): rvar, cvar = info.virtual, info.state if (rvar is None) or (cvar is None): continue is_surface = rvar.is_surface or cvar.is_surface dct = info.dc_type.type if not (dct in ('volume', 'scalar') or is_surface or info.is_trace or any_dof_conn): continue rreg_name = info.get_region_name(can_trace=False) creg_name = info.get_region_name() for rig, cig in info.iter_igs(): rname = rvar.get_primary_name() rkey = (rname, rreg_name, dct, rig, False) ckey = (cvar.name, creg_name, dct, cig, info.is_trace) dc_key = (rkey, ckey) ## print dc_key if not dc_key in shared: try: rdcs.append(adcs[rkey]) cdcs.append(adcs[ckey]) except: debug() shared.add(dc_key) return rdcs, cdcs
def solve_pressure_eigenproblem(self, mtx, eig_problem=None, n_eigs=0, check=False): """G = B*AI*BT or B*AI*BT+D""" def get_slice(n_eigs, nn): if n_eigs > 0: ii = slice(0, n_eigs) elif n_eigs < 0: ii = slice(nn + n_eigs, nn) else: ii = slice(0, 0) return ii eig_problem = get_default(eig_problem, self.eig_problem) n_eigs = get_default(n_eigs, self.n_eigs) check = get_default(check, self.check) mtx_c, mtx_b, action_aibt = mtx['C'], mtx['B'], mtx['action_aibt'] mtx_g = mtx_b * action_aibt.to_array() # mtx_b must be sparse! if eig_problem == 'B*AI*BT+D': mtx_g += mtx['D'].toarray() mtx['G'] = mtx_g output(mtx_c.shape, mtx_g.shape) eigs, mtx_q = eig(mtx_c.toarray(), mtx_g, method='eig.sgscipy') if check: ee = nm.diag(sc.dot(mtx_q.T * mtx_c, mtx_q)).squeeze() oo = nm.diag(sc.dot(sc.dot(mtx_q.T, mtx_g), mtx_q)).squeeze() try: assert_(nm.allclose(ee, eigs)) assert_(nm.allclose(oo, nm.ones_like(eigs))) except ValueError: debug() nn = mtx_c.shape[0] if isinstance(n_eigs, tuple): output('required number of eigenvalues: (%d, %d)' % n_eigs) if sum(n_eigs) < nn: ii0 = get_slice(n_eigs[0], nn) ii1 = get_slice(-n_eigs[1], nn) eigs = nm.concatenate((eigs[ii0], eigs[ii1])) mtx_q = nm.concatenate((mtx_q[:, ii0], mtx_q[:, ii1]), 1) else: output('required number of eigenvalues: %d' % n_eigs) if (n_eigs != 0) and (abs(n_eigs) < nn): ii = get_slice(n_eigs, nn) eigs = eigs[ii] mtx_q = mtx_q[:, ii] ## from sfepy.base.plotutils import pylab, iplot ## pylab.semilogy(eigs) ## pylab.figure(2) ## iplot(eigs) ## pylab.show() ## debug() out = Struct(eigs=eigs, mtx_q=mtx_q) return out
def __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_eigen_problem( self, ofn_trunk = None, post_process_hook = None ): if self.cached_evp is not None: return self.cached_evp problem = self.problem ofn_trunk = get_default( ofn_trunk, problem.ofn_trunk, 'output file name trunk missing!' ) post_process_hook = get_default( post_process_hook, self.post_process_hook ) conf = self.conf eig_problem = self.app_options.eig_problem if eig_problem in ['simple', 'simple_liquid']: problem.set_equations( conf.equations ) problem.time_update() problem.update_materials() mtx_a = problem.evaluate(conf.equations['lhs'], mode='weak', auto_init=True, dw_mode='matrix') mtx_m = problem.evaluate(conf.equations['rhs'], mode='weak', dw_mode='matrix') elif eig_problem == 'schur': # A = K + B^T D^{-1} B. mtx = assemble_by_blocks( conf.equations, self.problem, ebcs = conf.ebcs, epbcs = conf.epbcs ) problem.set_equations( conf.equations ) problem.time_update() problem.update_materials() ls = Solver.any_from_conf( problem.ls_conf, presolve = True, mtx = mtx['D'] ) mtx_b, mtx_m = mtx['B'], mtx['M'] mtx_dib = nm.empty( mtx_b.shape, dtype = mtx_b.dtype ) for ic in xrange( mtx_b.shape[1] ): mtx_dib[:,ic] = ls( mtx_b[:,ic].toarray().squeeze() ) mtx_a = mtx['K'] + mtx_b.T * mtx_dib else: raise NotImplementedError ## from sfepy.base.plotutils import spy, plt ## spy( mtx_b, eps = 1e-12 ) ## plt.show() ## mtx_a.save( 'a.txt', format='%d %d %.12f\n' ) ## mtx_b.save( 'b.txt', format='%d %d %.12f\n' ) ## pause() output( 'computing resonance frequencies...' ) tt = [0] if isinstance( mtx_a, sc.sparse.spmatrix ): mtx_a = mtx_a.toarray() if isinstance( mtx_m, sc.sparse.spmatrix ): mtx_m = mtx_m.toarray() eigs, mtx_s_phi = eig(mtx_a, mtx_m, return_time=tt, method=self.app_options.eigensolver) eigs[eigs<0.0] = 0.0 output( '...done in %.2f s' % tt[0] ) output( 'original eigenfrequencies:' ) output( eigs ) opts = self.app_options epsilon2 = opts.scale_epsilon * opts.scale_epsilon eigs_rescaled = (opts.elasticity_contrast / epsilon2) * eigs output( 'rescaled eigenfrequencies:' ) output( eigs_rescaled ) output( 'number of eigenfrequencies: %d' % eigs.shape[0] ) try: assert_( nm.isfinite( eigs ).all() ) except ValueError: debug() # B-orthogonality check. ## print nm.dot( mtx_s_phi[:,5], nm.dot( mtx_m, mtx_s_phi[:,5] ) ) ## print nm.dot( mtx_s_phi[:,5], nm.dot( mtx_m, mtx_s_phi[:,0] ) ) ## debug() n_eigs = eigs.shape[0] variables = problem.get_variables() mtx_phi = nm.empty( (variables.di.ptr[-1], mtx_s_phi.shape[1]), dtype = nm.float64 ) make_full = variables.make_full_vec if eig_problem in ['simple', 'simple_liquid']: for ii in xrange( n_eigs ): mtx_phi[:,ii] = make_full( mtx_s_phi[:,ii] ) eig_vectors = mtx_phi elif eig_problem == 'schur': # Update also eliminated variables. schur = self.app_options.schur primary_var = schur['primary_var'] eliminated_var = schur['eliminated_var'] mtx_s_phi_schur = - sc.dot( mtx_dib, mtx_s_phi ) aux = nm.empty( (variables.adi.ptr[-1],), dtype = nm.float64 ) set = variables.set_state_part for ii in xrange( n_eigs ): set( aux, mtx_s_phi[:,ii], primary_var, stripped = True ) set( aux, mtx_s_phi_schur[:,ii], eliminated_var, stripped = True ) mtx_phi[:,ii] = make_full( aux ) indx = variables.get_indx( primary_var ) eig_vectors = mtx_phi[indx,:] save = self.app_options.save out = {} state = problem.create_state() for ii in xrange( n_eigs ): if (ii >= save[0]) and (ii < (n_eigs - save[1])): continue state.set_full(mtx_phi[:,ii], force=True) aux = state.create_output_dict() for name, val in aux.iteritems(): out[name+'%03d' % ii] = val if post_process_hook is not None: out = post_process_hook( out, problem, mtx_phi ) problem.domain.mesh.write( ofn_trunk + '.vtk', io = 'auto', out = out ) fd = open( ofn_trunk + '_eigs.txt', 'w' ) eigs.tofile( fd, ' ' ) fd.close() evp = Struct( kind = eig_problem, eigs = eigs, eigs_rescaled = eigs_rescaled, eig_vectors = eig_vectors ) self.cached_evp = evp return evp
def main(): parser = OptionParser(usage=usage, version='%prog') parser.add_option('-b', '--basis', metavar='name', action='store', dest='basis', default='lagrange', help=help['basis']) parser.add_option('-n', '--max-order', metavar='order', type=int, action='store', dest='max_order', default=10, help=help['max_order']) parser.add_option('-m', '--matrix', metavar='type', action='store', dest='matrix_type', default='laplace', help=help['matrix_type']) parser.add_option('-g', '--geometry', metavar='name', action='store', dest='geometry', default='2_4', help=help['geometry']) options, args = parser.parse_args() dim, n_ep = int(options.geometry[0]), int(options.geometry[2]) output('reference element geometry:') output(' dimension: %d, vertices: %d' % (dim, n_ep)) n_c = {'laplace': 1, 'elasticity': dim}[options.matrix_type] output('matrix type:', options.matrix_type) output('number of variable components:', n_c) output('polynomial space:', options.basis) output('max. order:', options.max_order) mesh = Mesh.from_file(data_dir + '/meshes/elements/%s_1.mesh' % options.geometry) domain = Domain('domain', mesh) omega = domain.create_region('Omega', 'all') orders = nm.arange(1, options.max_order + 1, dtype=nm.int) conds = [] order_fix = 0 if options.geometry in ['2_4', '3_8'] else 1 for order in orders: output('order:', order, '...') field = Field.from_args('fu', nm.float64, n_c, omega, approx_order=order, space='H1', poly_space_base=options.basis) to = field.approx_order quad_order = 2 * (max(to - order_fix, 0)) output('quadrature order:', quad_order) u = FieldVariable('u', 'unknown', field, n_c) v = FieldVariable('v', 'test', field, n_c, primary_var_name='u') m = Material('m', lam=1.0, mu=1.0) integral = Integral('i', order=quad_order) if options.matrix_type == 'laplace': term = Term.new('dw_laplace(m.mu, v, u)', integral, omega, m=m, v=v, u=u) n_zero = 1 else: assert_(options.matrix_type == 'elasticity') term = Term.new('dw_lin_elastic_iso(m.lam, m.mu, v, u)', integral, omega, m=m, v=v, u=u) n_zero = (dim + 1) * dim / 2 term.setup() output('assembling...') tt = time.clock() mtx, iels = term.evaluate(mode='weak', diff_var='u') output('...done in %.2f s' % (time.clock() - tt)) mtx = mtx[0][0, 0] try: assert_(nm.max(nm.abs(mtx - mtx.T)) < 1e-10) except: from sfepy.base.base import debug debug() output('matrix shape:', mtx.shape) eigs = eig(mtx, method='eig.sgscipy', eigenvectors=False) eigs.sort() # Zero 'true' zeros. eigs[:n_zero] = 0.0 ii = nm.where(eigs < 0.0)[0] if len(ii): output('matrix is not positive semi-definite!') ii = nm.where(eigs[n_zero:] < 1e-12)[0] if len(ii): output('matrix has more than %d zero eigenvalues!' % n_zero) output('smallest eigs:\n', eigs[:10]) ii = nm.where(eigs > 0.0)[0] emin, emax = eigs[ii[[0, -1]]] output('min:', emin, 'max:', emax) cond = emax / emin conds.append(cond) output('condition number:', cond) output('...done') plt.figure(1) plt.semilogy(orders, conds) plt.xticks(orders, orders) plt.xlabel('polynomial order') plt.ylabel('condition number') plt.grid() plt.figure(2) plt.loglog(orders, conds) plt.xticks(orders, orders) plt.xlabel('polynomial order') plt.ylabel('condition number') plt.grid() plt.show()