def __init__(self, conf, context=None, **kwargs): NonlinearSolver.__init__(self, conf, context=context, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) conf.problem = context conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration'], [r'$\gamma$', r'$\max(\delta)$', r'$\max(\tau)$']], xlabels=['', '', 'all iterations'], ylabels=[r'$||r||$', 'iteration', 'stabilization'], yscales=['log', 'linear', 'log'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d'], ['%.8e', '%.8e', '%.8e']]) else: self.log = None
def test_log_create(self): from sfepy.base.log import Log log = Log([['x^3']], plot_kwargs=[{ 'color': 'b', 'ls': '', 'marker': 'o' }], yscales=['linear'], xlabels=['x'], ylabels=['a cubic function'], is_plot=False, aggregate=0, sleep=0.0, log_filename=self.log_filename, formats=[['{:.5e}']]) for x in nm.linspace(0, 1, 11): log(x**3, x=[x]) if nm.allclose(x, 0.5): log.plot_vlines([0], color='g', linewidth=2) log(finished=True) return True
def main(): cwd = os.path.split(os.path.join(os.getcwd(), __file__))[0] log = Log((['sin(x) + i sin(x**2)', 'cos(x)'], ['exp(x)']), yscales=['linear', 'log'], xlabels=['angle', None], ylabels=[None, 'a function'], aggregate=1000, sleep=0.05, log_filename=os.path.join(cwd, 'live_plot.log')) log2 = Log([['x^3']], yscales=['linear'], xlabels=['x'], ylabels=['a cubic function'], aggregate=1000, sleep=0.05, log_filename=os.path.join(cwd, 'live_plot2.log'), formats=[['{:.5e}']]) added = 0 for x in nm.linspace(0, 4.0 * nm.pi, 200): output('x: ', x) if x < (2.0 * nm.pi): log(nm.sin(x) + 1j * nm.sin(x**2), nm.cos(x), nm.exp(x), x=[x, None]) else: if added: log(nm.sin(x) + 1j * nm.sin(x**2), nm.cos(x), nm.exp(x), x**2, x=[x, None, x]) else: log.plot_vlines(color='r', linewidth=2) log.add_group(['x^2'], yscale='linear', xlabel='new x', ylabel='square', formats=['%+g']) added += 1 if (added == 20) or (added == 50): log.plot_vlines([2], color='g', linewidth=2) log2(x * x * x, x=[x]) print(log) print(log2) pause() log(finished=True) log2(finished=True)
def __init__(self, conf, **kwargs): OptimizationSolver.__init__(self, conf, **kwargs) conf = self.conf if conf.is_any_log: self.log = Log( [[r'$||\Psi||$'], [r'$||\nabla \Psi||$'], [r'$\alpha$'], ['iteration']], xlabels=['', '', 'all iterations', 'all iterations'], yscales=conf.yscales, is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%.3e'], ['%.3e'], ['%d']]) else: self.log = None
def __init__(self, conf, **kwargs): NonlinearSolver.__init__( self, conf, **kwargs ) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration']], xlabels=['', 'all iterations'], ylabels=[r'$||r||$', 'iteration'], yscales=['log', 'linear'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d']]) else: self.log = None
def __init__(self, conf, problem, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) conf.problem = problem conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration'], [r'$\gamma$', r'$\max(\delta)$', r'$\max(\tau)$']], xlabels=['', '', 'all iterations'], ylabels=[r'$||r||$', 'iteration', 'stabilization'], yscales=['log', 'linear', 'log'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d'], ['%.8e', '%.8e', '%.8e']]) else: self.log = None
def __init__(self, conf, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration'], [r'$\gamma$', r'$\max(\delta)$', r'$\max(\tau)$']], xlabels=['', '', 'all iterations'], ylabels=[r'$||r||$', 'iteration', 'stabilization'], yscales=['log', 'linear', 'log'], log_filename=conf.log.text, formats=[['%.8e'], ['%d'], ['%.8e', '%.8e', '%.8e']]) else: self.log = None
def vary_incident_wave_dir( problem ): default_printer.prefix = 'vary_incident_wave_dir:' log_conf = { 'is_plot' : True, 'yscales' : ['linear'], 'xaxes' : ['incident wave angle [degrees]'], 'yaxes' : ['phase velocity [m/s]'], } dim = problem.domain.mesh.dim log = Log.from_conf( log_conf, ['phase velocity %d' % ii for ii in range( dim )] ) alphas = nm.linspace( 0.0, 360.0, 37 ) output( 'running for angles:', alphas ) pause() for ii, alpha in enumerate( alphas ): output( 'iteration %d: alpha %2f' % (ii, alpha) ) opts = problem.conf.options ra = nm.pi * alpha / 180.0 iwd = nm.zeros( (dim,), dtype = nm.float64 ) iwd[0:2] = [nm.cos( ra ), nm.sin( ra )] opts.incident_wave_dir = iwd out = [] yield problem, out #You have: sqrt( 10^10Pa / 10^4kg * m^3 ) #You want: #Definition: 1000 m / s convert_to_ms = 1000.0 phase_velocity = out[0] * convert_to_ms # to m/s. log( x = [alpha], *phase_velocity ) output( 'phase velocity [m/s]:', phase_velocity ) if opts.homogeneous: mat = problem.materials['matrix'] # dilatation wave: vp = \sqrt{ (\lambda + 2\mu) / \rho } vd = nm.sqrt( (mat.D[0,0]) / mat.density) * convert_to_ms # shear wave: vs = \sqrt{ \mu / \rho } vs = nm.sqrt( mat.D[-1,-1] / mat.density ) * convert_to_ms output( 'analytical dilatation: %f, shear: %f' % (vd, vs) ) # pause() yield None print log pause() if opts.homogeneous: name = 'homogeneous' else: name = 'perforated' fig_name = os.path.join( problem.output_dir, 'phase_velocity_%s%s' % (name, opts.fig_suffix) ) log( save_figure = fig_name, finished = True )
def iter_step(self, x, first_step=False): if first_step: self.log = Log([['O'], ['E_f', 'E_m'], ['v_f', 'v_m']], ylabels=['Obj. fun.', "Young's modulus", "Poisson's ratio"], xlabels=['iter', 'iter', 'iter'], aggregate=0) self.istep = 0 self.log(0.5, x[0], x[2], x[1], x[3], x=[0, 0, 0, 0]) else: self.istep += 1 self.log(self.eval_f[-1], x[0], x[2], x[1], x[3], x=(self.istep,)*4)
def __init__(self, conf, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration']], xlabels=['', 'all iterations'], ylabels=[r'$||r||$', 'iteration'], yscales=['log', 'linear'], log_filename=conf.log.text, formats=[['%.8e'], ['%d']]) else: self.log = None
def __init__( self, conf, **kwargs ): OptimizationSolver.__init__( self, conf, **kwargs ) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||\Psi||$'], [r'$||\nabla \Psi||$'], [r'$\alpha$'], ['iteration']], xlabels=['', '', 'all iterations', 'all iterations'], yscales=conf.yscales, is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%.3e'], ['%.3e'], ['%d']]) else: self.log = None
def __init__(self, conf, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf if conf.is_any_log: self.log = Log( [[r"$||r||$"], ["iteration"]], xlabels=["", "all iterations"], ylabels=[r"$||r||$", "iteration"], yscales=["log", "linear"], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[["%.8e"], ["%d"]], ) else: self.log = None
def main(): cwd = os.path.split(os.path.join(os.getcwd(), __file__))[0] log = Log( (["sin(x)", "cos(x)"], ["exp(x)"]), yscales=["linear", "log"], xlabels=["angle", None], ylabels=[None, "a function"], log_filename=os.path.join(cwd, "live_plot.log"), ) log2 = Log( [["x^3"]], yscales=["linear"], xlabels=["x"], ylabels=["a cubic function"], log_filename=os.path.join(cwd, "live_plot2.log"), ) added = 0 for x in nm.linspace(0, 4.0 * nm.pi, 200): output("x: ", x) if x < (2.0 * nm.pi): log(nm.sin(x), nm.cos(x), nm.exp(x), x=[x, None]) else: if added: log(nm.sin(x), nm.cos(x), nm.exp(x), x ** 2, x=[x, None, x]) else: log.plot_vlines(color="r", linewidth=2) log.add_group(["x^2"], "linear", "new x", "square", formats=["%+g"]) added += 1 if (added == 20) or (added == 50): log.plot_vlines([2], color="g", linewidth=2) log2(x * x * x, x=[x]) print log print log2 pause() log(finished=True) log2(finished=True)
def main(): log_conf = { 'is_plot' : True, 'aggregate' : 200, 'yscales' : ['linear', 'log'], 'xaxes' : ['angle', None], 'yaxes' : [None, 'a function'], } log = Log.from_conf( log_conf, (['sin( x )', 'cos( x )'],['exp( x )']) ) for x in nm.linspace( 0, 4.0 * nm.pi, 200 ): output( 'x: ', x ) log( nm.sin( x ), nm.cos( x ), nm.exp( x ), x = [x, None] ) print log pause() log( finished = True )
def __init__(self, conf, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration']], xlabels=['', 'all iterations'], ylabels=[r'$||r||$', 'iteration'], yscales=['log', 'linear'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d']]) else: self.log = None
def main(): cwd = os.path.split(os.path.join(os.getcwd(), __file__))[0] log = Log((['sin(x) + i sin(x**2)', 'cos(x)'], ['exp(x)']), yscales=['linear', 'log'], xlabels=['angle', None], ylabels=[None, 'a function'], log_filename=os.path.join(cwd, 'live_plot.log')) log2 = Log([['x^3']], yscales=['linear'], xlabels=['x'], ylabels=['a cubic function'], aggregate=50, sleep=0.05, log_filename=os.path.join(cwd, 'live_plot2.log'), formats=[['{:.5e}']]) added = 0 for x in nm.linspace(0, 4.0 * nm.pi, 200): output('x: ', x) if x < (2.0 * nm.pi): log(nm.sin(x)+1j*nm.sin(x**2), nm.cos(x), nm.exp(x), x=[x, None]) else: if added: log(nm.sin(x)+1j*nm.sin(x**2), nm.cos(x), nm.exp(x), x**2, x=[x, None, x]) else: log.plot_vlines(color='r', linewidth=2) log.add_group(['x^2'], yscale='linear', xlabel='new x', ylabel='square', formats=['%+g']) added += 1 if (added == 20) or (added == 50): log.plot_vlines([2], color='g', linewidth=2) log2(x*x*x, x=[x]) print(log) print(log2) pause() log(finished=True) log2(finished=True)
class Oseen( NonlinearSolver ): name = 'nls.oseen' @staticmethod def process_conf(conf, kwargs): """ Missing items are set to default values. Example configuration, all items:: solver_1 = { 'name' : 'oseen', 'kind' : 'nls.oseen', 'needs_problem_instance' : True, 'stabil_mat' : 'stabil', 'adimensionalize' : False, 'check_navier_stokes_rezidual' : False, 'i_max' : 10, 'eps_a' : 1e-8, 'eps_r' : 1.0, 'macheps' : 1e-16, 'lin_red' : 1e-2, # Linear system error < (eps_a * lin_red). 'is_plot' : False, 'log' : {'text' : 'oseen_log.txt', 'plot' : 'oseen_log.png'}, } """ get = make_get_conf(conf, kwargs) common = NonlinearSolver.process_conf(conf) # Compulsory. needs_problem_instance = get('needs_problem_instance', True) if not needs_problem_instance: msg = 'set solver option "needs_problem_instance" to True!' raise ValueError(msg) stabil_mat = get('stabil_mat', None, 'missing "stabil_mat" in options!') # With defaults. adimensionalize = get('adimensionalize', False) if adimensionalize: raise NotImplementedError check = get('check_navier_stokes_rezidual', False) log = get_logging_conf(conf) log = Struct(name='log_conf', **log) is_any_log = (log.text is not None) or (log.plot is not None) return Struct(needs_problem_instance=needs_problem_instance, stabil_mat=stabil_mat, adimensionalize=adimensionalize, check_navier_stokes_rezidual=check, i_max=get('i_max', 1), eps_a=get('eps_a', 1e-10), eps_r=get('eps_r', 1.0), macheps=get('macheps', nm.finfo(nm.float64).eps), lin_red=get('lin_red', 1.0), lin_precision=get('lin_precision', None), is_plot=get('is_plot', False), log=log, is_any_log=is_any_log) + common def __init__( self, conf, **kwargs ): NonlinearSolver.__init__( self, conf, **kwargs ) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration'], [r'$\gamma$', r'$\max(\delta)$', r'$\max(\tau)$']], xlabels=['', '', 'all iterations'], ylabels=[r'$||r||$', 'iteration', 'stabilization'], yscales=['log', 'linear', 'log'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d'], ['%.8e', '%.8e', '%.8e']]) else: self.log = None 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. """ 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 ) status = get_default( status, self.status ) problem = get_default( problem, self.problem ) if problem is None: msg = 'set solver option "needs_problem_instance" to True!' raise ValueError(msg) time_stats = {} stabil = problem.get_materials()[conf.stabil_mat] ns, ii = stabil.function.function.get_maps() variables = problem.get_variables() update_var = variables.set_data_from_state make_full_vec = variables.make_full_vec print 'problem size:' print ' velocity: %s' % ii['us'] print ' 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 ) print '|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 ) print '|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() ) ) print 'stabilization parameters:' print ' gamma: %.12e' % max_pars[ns['gamma']] print ' max( delta ): %.12e' % max_pars[ns['delta']] print ' max( tau ): %.12e' % max_pars[ns['tau']] if (not are_close( b_norm, 1.0 )) and conf.adimensionalize: adimensionalize = True else: adimensionalize = False tt = time.clock() try: vec_r = fun( vec_x ) except ValueError: ok = False else: ok = True time_stats['rezidual'] = time.clock() - tt if ok: err = nla.norm( vec_r ) if it == 0: err0 = err; else: err += nla.norm( vec_dx ) else: # Failure. output( 'rezidual 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 tt = time.clock() try: mtx_a = fun_grad( vec_x ) except ValueError: ok = False else: ok = True time_stats['matrix'] = time.clock() - tt if not ok: raise RuntimeError( 'giving up...' ) tt = time.clock() vec_dx = lin_solver(vec_r, x0=vec_x, mtx=mtx_a) time_stats['solve'] = time.clock() - tt 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 time_stats.iteritems(): output( '%10s: %7.2f [s]' % kv ) vec_x_prev = vec_x.copy() 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_prev ) 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 conf.check_navier_stokes_rezidual: 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: print 'Navier-Stokes rezidual computation failed!' err_ns = err_ns0 = None else: err_ns0 = nla.norm( vec_rns0 ) err_ns = nla.norm( vec_rns ) print 'Navier-Stokes rezidual0: %.8e' % err_ns0 print 'Navier-Stokes rezidual : %.8e' % err_ns print 'b - u: %.8e' % nla.norm( vec_b - vec_u ) print condition ## print vec_rns - vec_rns1 plu.plt.ion() plu.plt.gcf().clear() plu.plt.plot( vec_rns ) ## plu.plt.gcf().clear() ## plu.plt.plot( vec_rns1 ) plu.plt.draw() plu.plt.ioff() pause() 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 solve_eigen_problem_n( conf, options ): pb = ProblemDefinition.from_conf( conf ) dim = pb.domain.mesh.dim pb.time_update() dummy = pb.create_state_vector() output( 'assembling rhs...' ) tt = time.clock() mtx_b = eval_term_op( dummy, conf.equations['rhs'], pb, dw_mode = 'matrix', tangent_matrix = pb.mtx_a.copy() ) output( '...done in %.2f s' % (time.clock() - tt) ) #mtxA.save( 'tmp/a.txt', format='%d %d %.12f\n' ) #mtxB.save( 'tmp/b.txt', format='%d %d %.12f\n' ) try: n_eigs = conf.options.n_eigs except AttributeError: n_eigs = mtx_a.shape[0] if n_eigs is None: n_eigs = mtx_a.shape[0] ## mtx_a.save( 'a.txt', format='%d %d %.12f\n' ) ## mtx_b.save( 'b.txt', format='%d %d %.12f\n' ) if options.plot: log_conf = { 'is_plot' : True, 'aggregate' : 1, 'yscales' : ['linear', 'log'], } else: log_conf = { 'is_plot' : False, } log = Log.from_conf( log_conf, ([r'$|F(x)|$'], [r'$|F(x)|$']) ) eig_conf = pb.get_solver_conf( conf.options.eigen_solver ) eig_solver = Solver.any_from_conf( eig_conf ) vec_vhxc = nm.zeros( (pb.variables.di.ptr[-1],), dtype = nm.float64 ) aux = wrap_function( iterate, (pb, conf, eig_solver, n_eigs, mtx_b, log) ) ncalls, times, nonlin_v = aux vec_vhxc = broyden3( nonlin_v, vec_vhxc, verbose = True ) out = iterate( vec_vhxc, pb, conf, eig_solver, n_eigs, mtx_b ) eigs, mtx_s_phi, vec_n, vec_vh, vec_vxc = out if options.plot: log( finished = True ) pause() coor = pb.domain.get_mesh_coors() r = coor[:,0]**2 + coor[:,1]**2 + coor[:,2]**2 vec_nr2 = vec_n * r n_eigs = eigs.shape[0] mtx_phi = nm.empty( (pb.variables.di.ptr[-1], mtx_s_phi.shape[1]), dtype = nm.float64 ) for ii in xrange( n_eigs ): mtx_phi[:,ii] = pb.variables.make_full_vec( mtx_s_phi[:,ii] ) save = get_default_attr( conf.options, 'save_eig_vectors', None ) out = {} for ii in xrange( n_eigs ): if save is not None: if (ii >= save[0]) and (ii < (n_eigs - save[1])): continue aux = pb.state_to_output( mtx_phi[:,ii] ) key = aux.keys()[0] out[key+'%03d' % ii] = aux[key] update_state_to_output( out, pb, vec_n, 'n' ) update_state_to_output( out, pb, vec_nr2, 'nr2' ) update_state_to_output( out, pb, vec_vh, 'vh' ) update_state_to_output( out, pb, vec_vxc, 'vxc' ) ofn_trunk = options.output_filename_trunk pb.domain.mesh.write( ofn_trunk + '.vtk', io = 'auto', out = out ) fd = open( ofn_trunk + '_eigs.txt', 'w' ) eigs.tofile( fd, ' ' ) fd.close() return Struct( pb = pb, eigs = eigs, mtx_phi = mtx_phi )
class Newton(NonlinearSolver): r""" Solves a nonlinear system :math:`f(x) = 0` using the Newton method with backtracking line-search, starting with an initial guess :math:`x^0`. """ name = 'nls.newton' __metaclass__ = SolverMeta _parameters = [ ('i_max', 'int', 1, False, 'The maximum number of iterations.'), ('eps_a', 'float', 1e-10, False, 'The absolute tolerance for the residual, i.e. :math:`||f(x^i)||`.'), ('eps_r', 'float', 1.0, False, """The relative tolerance for the residual, i.e. :math:`||f(x^i)|| / ||f(x^0)||`."""), ('eps_mode', "'and' or 'or'", 'and', False, """The logical operator to use for combining the absolute and relative tolerances."""), ('macheps', 'float', nm.finfo(nm.float64).eps, False, 'The float considered to be machine "zero".'), ('lin_red', 'float', 1.0, False, """The linear system solution error should be smaller than (`eps_a` * `lin_red`), otherwise a warning is printed."""), ('lin_precision', 'float or None', None, False, """If not None, the linear system solution tolerances are set in each nonlinear iteration relative to the current residual norm by the `lin_precision` factor. Ignored for direct linear solvers."""), ('ls_on', 'float', 0.99999, False, """Start the backtracking line-search by reducing the step, if :math:`||f(x^i)|| / ||f(x^{i-1})||` is larger than `ls_on`."""), ('ls_red', '0.0 < float < 1.0', 0.1, False, 'The step reduction factor in case of correct residual assembling.'), ('ls_red_warp', '0.0 < float < 1.0', 0.001, False, """The step reduction factor in case of failed residual assembling (e.g. the "warp violation" error caused by a negative volume element resulting from too large deformations)."""), ('ls_min', '0.0 < float < 1.0', 1e-5, False, 'The minimum step reduction factor.'), ('give_up_warp', 'bool', False, False, 'If True, abort on the "warp violation" error.'), ('check', '0, 1 or 2', 0, False, """If >= 1, check the tangent matrix using finite differences. If 2, plot the resulting sparsity patterns."""), ('delta', 'float', 1e-6, False, r"""If `check >= 1`, the finite difference matrix is taken as :math:`A_{ij} = \frac{f_i(x_j + \delta) - f_i(x_j - \delta)}{2 \delta}`."""), ('log', 'dict or None', None, False, """If not None, log the convergence according to the configuration in the following form: ``{'text' : 'log.txt', 'plot' : 'log.pdf'}``. Each of the dict items can be None."""), ('is_linear', 'bool', False, False, 'If True, the problem is considered to be linear.'), ] def __init__(self, conf, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration']], xlabels=['', 'all iterations'], ylabels=[r'$||r||$', 'iteration'], yscales=['log', 'linear'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d']]) else: self.log = None 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 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) 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('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['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
class FMinSteepestDescent(OptimizationSolver): """ Steepest descent optimization solver. """ name = 'opt.fmin_sd' __metaclass__ = SolverMeta _parameters = [ ('i_max', 'int', 10, False, 'The maximum number of iterations.'), ('eps_rd', 'float', 1e-5, False, 'The relative delta of the objective function.'), ('eps_of', 'float', 1e-4, False, 'The tolerance for the objective function.'), ('eps_ofg', 'float', 1e-8, False, 'The tolerance for the objective function gradient.'), ('norm', 'numpy norm', nm.Inf, False, 'The norm to be used.'), ('ls', 'bool', True, False, 'If True, use a line-search.'), ('ls_method', "{'backtracking', 'full'}", 'backtracking', False, 'The line-search method.'), ('ls_on', 'float', 0.99999, False, """Start the backtracking line-search by reducing the step, if :math:`||f(x^i)|| / ||f(x^{i-1})||` is larger than `ls_on`."""), ('ls0', '0.0 < float < 1.0', 1.0, False, 'The initial step.'), ('ls_red', '0.0 < float < 1.0', 0.5, False, 'The step reduction factor in case of correct residual assembling.'), ('ls_red_warp', '0.0 < float < 1.0', 0.1, False, """The step reduction factor in case of failed residual assembling (e.g. the "warp violation" error caused by a negative volume element resulting from too large deformations)."""), ('ls_min', '0.0 < float < 1.0', 1e-5, False, 'The minimum step reduction factor.'), ('check', '0, 1 or 2', 0, False, """If >= 1, check the tangent matrix using finite differences. If 2, plot the resulting sparsity patterns."""), ('delta', 'float', 1e-6, False, r"""If `check >= 1`, the finite difference matrix is taken as :math:`A_{ij} = \frac{f_i(x_j + \delta) - f_i(x_j - \delta)}{2 \delta}`."""), ('output', 'function', None, False, """If given, use it instead of :func:`output() <sfepy.base.base.output()>` function."""), ('yscales', 'list of str', ['linear', 'log', 'log', 'linear'], False, 'The list of four convergence log subplot scales.'), ('log', 'dict or None', None, False, """If not None, log the convergence according to the configuration in the following form: ``{'text' : 'log.txt', 'plot' : 'log.pdf'}``. Each of the dict items can be None."""), ] def __init__(self, conf, **kwargs): OptimizationSolver.__init__(self, conf, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) if conf.is_any_log: self.log = Log([[r'$||\Psi||$'], [r'$||\nabla \Psi||$'], [r'$\alpha$'], ['iteration']], xlabels=['', '', 'all iterations', 'all iterations'], yscales=conf.yscales, is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%.3e'], ['%.3e'], ['%d']]) else: self.log = None 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) 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: tt = time.clock() check_gradient(xit, ofg, fn_of, conf.delta, conf.check) time_stats['check'].append(time.clock() - tt) 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 time_stats.iteritems(): 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 main(): # Aluminium and epoxy. default_pars = '70e9,0.35,2.799e3, 3.8e9,0.27,1.142e3' default_solver_conf = ("kind='eig.scipy',method='eigh',tol=1.0e-5," "maxiter=1000,which='LM',sigma=0.0") parser = ArgumentParser(description=__doc__, formatter_class=RawDescriptionHelpFormatter) parser.add_argument('--pars', metavar='young1,poisson1,density1' ',young2,poisson2,density2', action='store', dest='pars', default=default_pars, help=helps['pars']) parser.add_argument('--conf', metavar='filename', action='store', dest='conf', default=None, help=helps['conf']) parser.add_argument('--mesh-size', type=float, metavar='float', action='store', dest='mesh_size', default=None, help=helps['mesh_size']) parser.add_argument('--unit-multipliers', metavar='c_time,c_length,c_mass', action='store', dest='unit_multipliers', default='1.0,1.0,1.0', help=helps['unit_multipliers']) parser.add_argument('--plane', action='store', dest='plane', choices=['strain', 'stress'], default='strain', help=helps['plane']) parser.add_argument('--wave-dir', metavar='float,float[,float]', action='store', dest='wave_dir', default='1.0,0.0,0.0', help=helps['wave_dir']) parser.add_argument('--mode', action='store', dest='mode', choices=['omega', 'kappa'], default='omega', help=helps['mode']) parser.add_argument('--range', metavar='start,stop,count', action='store', dest='range', default='10,100,10', help=helps['range']) parser.add_argument('--order', metavar='int', type=int, action='store', dest='order', default=1, help=helps['order']) parser.add_argument('--refine', metavar='int', type=int, action='store', dest='refine', default=0, help=helps['refine']) parser.add_argument('-n', '--n-eigs', metavar='int', type=int, action='store', dest='n_eigs', default=6, help=helps['n_eigs']) parser.add_argument('--eigs-only', action='store_true', dest='eigs_only', default=False, help=helps['eigs_only']) parser.add_argument('--solver-conf', metavar='dict-like', action='store', dest='solver_conf', default=default_solver_conf, help=helps['solver_conf']) parser.add_argument('--save-materials', action='store_true', dest='save_materials', default=False, help=helps['save_materials']) parser.add_argument('--log-std-waves', action='store_true', dest='log_std_waves', default=False, help=helps['log_std_waves']) parser.add_argument('--silent', action='store_true', dest='silent', default=False, help=helps['silent']) parser.add_argument('-c', '--clear', action='store_true', dest='clear', default=False, help=helps['clear']) parser.add_argument('-o', '--output-dir', metavar='path', action='store', dest='output_dir', default='output', help=helps['output_dir']) parser.add_argument('mesh_filename', default='', help=helps['mesh_filename']) options = parser.parse_args() output_dir = options.output_dir output.set_output(filename=os.path.join(output_dir, 'output_log.txt'), combined=options.silent == False) if options.conf is not None: mod = import_file(options.conf) apply_units = mod.apply_units define = mod.define set_wave_dir = mod.set_wave_dir else: apply_units = apply_units_le define = define_le set_wave_dir = set_wave_dir_le options.pars = [float(ii) for ii in options.pars.split(',')] options.unit_multipliers = [ float(ii) for ii in options.unit_multipliers.split(',') ] options.wave_dir = [float(ii) for ii in options.wave_dir.split(',')] aux = options.range.split(',') options.range = [float(aux[0]), float(aux[1]), int(aux[2])] options.solver_conf = dict_from_string(options.solver_conf) if options.clear: remove_files_patterns(output_dir, ['*.h5', '*.vtk', '*.txt'], ignores=['output_log.txt'], verbose=True) filename = os.path.join(output_dir, 'options.txt') ensure_path(filename) save_options(filename, [('options', vars(options))]) pars = apply_units(options.pars, options.unit_multipliers) output('material parameters with applied unit multipliers:') output(pars) if options.mode == 'omega': rng = copy(options.range) rng[:2] = apply_unit_multipliers(options.range[:2], ['wave_number', 'wave_number'], options.unit_multipliers) output('wave number range with applied unit multipliers:', rng) else: rng = copy(options.range) rng[:2] = apply_unit_multipliers(options.range[:2], ['frequency', 'frequency'], options.unit_multipliers) output('frequency range with applied unit multipliers:', rng) define_problem = functools.partial(define, filename_mesh=options.mesh_filename, pars=pars, approx_order=options.order, refinement_level=options.refine, solver_conf=options.solver_conf, plane=options.plane) conf = ProblemConf.from_dict(define_problem(), sys.modules[__name__]) pb = Problem.from_conf(conf) dim = pb.domain.shape.dim if dim != 2: options.plane = 'strain' wdir = nm.asarray(options.wave_dir[:dim], dtype=nm.float64) wdir = wdir / nm.linalg.norm(wdir) stepper = TimeStepper(rng[0], rng[1], dt=None, n_step=rng[2]) bbox = pb.domain.mesh.get_bounding_box() size = (bbox[1] - bbox[0]).max() scaling0 = apply_unit_multipliers([1.0], ['length'], options.unit_multipliers)[0] scaling = scaling0 if options.mesh_size is not None: scaling *= options.mesh_size / size output('scaling factor of periodic cell mesh coordinates:', scaling) output('new mesh size with applied unit multipliers:', scaling * size) pb.domain.mesh.coors[:] *= scaling pb.set_mesh_coors(pb.domain.mesh.coors, update_fields=True) bzone = 2.0 * nm.pi / (scaling * size) output('1. Brillouin zone size:', bzone * scaling0) output('1. Brillouin zone size with applied unit multipliers:', bzone) pb.time_update() pb.update_materials() if options.save_materials or options.log_std_waves: stiffness = pb.evaluate('ev_integrate_mat.2.Omega(m.D, u)', mode='el_avg', copy_materials=False, verbose=False) young, poisson = mc.youngpoisson_from_stiffness(stiffness, plane=options.plane) density = pb.evaluate('ev_integrate_mat.2.Omega(m.density, u)', mode='el_avg', copy_materials=False, verbose=False) if options.save_materials: out = {} out['young'] = Struct(name='young', mode='cell', data=young[..., None, None]) out['poisson'] = Struct(name='poisson', mode='cell', data=poisson[..., None, None]) out['density'] = Struct(name='density', mode='cell', data=density) materials_filename = os.path.join(output_dir, 'materials.vtk') pb.save_state(materials_filename, out=out) # Set the normalized wave vector direction to the material(s). set_wave_dir(pb.get_materials(), wdir) conf = pb.solver_confs['eig'] eig_solver = Solver.any_from_conf(conf) # Assemble the matrices. mtx_m = pb.mtx_a.copy() eq_m = pb.equations['M'] mtx_m = eq_m.evaluate(mode='weak', dw_mode='matrix', asm_obj=mtx_m) mtx_m.eliminate_zeros() mtx_k = pb.mtx_a.copy() eq_k = pb.equations['K'] mtx_k = eq_k.evaluate(mode='weak', dw_mode='matrix', asm_obj=mtx_k) mtx_k.eliminate_zeros() mtx_s = pb.mtx_a.copy() eq_s = pb.equations['S'] mtx_s = eq_s.evaluate(mode='weak', dw_mode='matrix', asm_obj=mtx_s) mtx_s.eliminate_zeros() mtx_r = pb.mtx_a.copy() eq_r = pb.equations['R'] mtx_r = eq_r.evaluate(mode='weak', dw_mode='matrix', asm_obj=mtx_r) mtx_r.eliminate_zeros() output('symmetry checks of real blocks:') output('M - M^T:', _max_diff_csr(mtx_m, mtx_m.T)) output('K - K^T:', _max_diff_csr(mtx_k, mtx_k.T)) output('S - S^T:', _max_diff_csr(mtx_s, mtx_s.T)) output('R + R^T:', _max_diff_csr(mtx_r, -mtx_r.T)) n_eigs = options.n_eigs if options.n_eigs > mtx_k.shape[0]: options.n_eigs = mtx_k.shape[0] n_eigs = None if options.mode == 'omega': eigenshapes_filename = os.path.join( output_dir, 'frequency-eigenshapes-%s.vtk' % stepper.suffix) extra = [] extra_plot_kwargs = [] if options.log_std_waves: lam, mu = mc.lame_from_youngpoisson(young, poisson, plane=options.plane) alam = nm.average(lam) amu = nm.average(mu) adensity = nm.average(density) cp = nm.sqrt((alam + 2.0 * amu) / adensity) cs = nm.sqrt(amu / adensity) output('average p-wave speed:', cp) output('average shear wave speed:', cs) extra = [r'$\omega_p$', r'$\omega_s$'] extra_plot_kwargs = [{ 'ls': '--', 'color': 'k' }, { 'ls': '--', 'color': 'gray' }] log = Log( [[r'$\lambda_{%d}$' % ii for ii in range(options.n_eigs)], [r'$\omega_{%d}$' % ii for ii in range(options.n_eigs)] + extra], plot_kwargs=[{}, [{}] * options.n_eigs + extra_plot_kwargs], yscales=['linear', 'linear'], xlabels=[r'$\kappa$', r'$\kappa$'], ylabels=[r'eigenvalues $\lambda_i$', r'frequencies $\omega_i$'], log_filename=os.path.join(output_dir, 'frequencies.txt'), aggregate=1000, sleep=0.1) for iv, wmag in stepper: output('step %d: wave vector %s' % (iv, wmag * wdir)) mtx_a = mtx_k + wmag**2 * mtx_s + (1j * wmag) * mtx_r mtx_b = mtx_m output('A - A^H:', _max_diff_csr(mtx_a, mtx_a.H)) if options.eigs_only: eigs = eig_solver(mtx_a, mtx_b, n_eigs=n_eigs, eigenvectors=False) svecs = None else: eigs, svecs = eig_solver(mtx_a, mtx_b, n_eigs=options.n_eigs, eigenvectors=True) omegas = nm.sqrt(eigs) output('eigs, omegas:\n', nm.c_[eigs, omegas]) out = tuple(eigs) + tuple(omegas) if options.log_std_waves: out = out + (cp * wmag, cs * wmag) log(*out, x=[wmag, wmag]) save_eigenvectors(eigenshapes_filename % iv, svecs, pb) log(save_figure=os.path.join(output_dir, 'frequencies.png')) log(finished=True) else: import scipy.sparse as sps from sksparse.cholmod import cholesky eigenshapes_filename = os.path.join( output_dir, 'wave-number-eigenshapes-%s.vtk' % stepper.suffix) factor = cholesky(mtx_s) perm = factor.P() ir = nm.arange(len(perm)) mtx_p = sps.coo_matrix((nm.ones_like(perm), (ir, perm))) mtx_l = mtx_p.T * factor.L() mtx_eye = sps.eye(mtx_l.shape[0], dtype=nm.float64) output('S - LL^T:', _max_diff_csr(mtx_s, mtx_l * mtx_l.T)) log = Log([[r'$\kappa_{%d}$' % ii for ii in range(options.n_eigs)]], plot_kwargs=[{ 'ls': 'None', 'marker': 'o' }], yscales=['linear'], xlabels=[r'$\omega$'], ylabels=[r'wave numbers $\kappa_i$'], log_filename=os.path.join(output_dir, 'wave-numbers.txt'), aggregate=1000, sleep=0.1) for io, omega in stepper: output('step %d: frequency %s' % (io, omega)) mtx_a = sps.bmat([[mtx_k - omega**2 * mtx_m, None], [None, mtx_eye]]) mtx_b = sps.bmat([[1j * mtx_r, mtx_l], [mtx_l.T, None]]) output('A - A^T:', _max_diff_csr(mtx_a, mtx_a.T)) output('A - A^H:', _max_diff_csr(mtx_a, mtx_a.T)) output('B - B^H:', _max_diff_csr(mtx_b, mtx_b.H)) if options.eigs_only: eigs = eig_solver(mtx_a, mtx_b, n_eigs=n_eigs, eigenvectors=False) svecs = None else: eigs, svecs = eig_solver(mtx_a, mtx_b, n_eigs=options.n_eigs, eigenvectors=True) kappas = eigs output('kappas:\n', kappas[:, None]) out = tuple(kappas) log(*out, x=[omega]) save_eigenvectors(eigenshapes_filename % io, svecs, pb) log(save_figure=os.path.join(output_dir, 'wave-numbers.png')) log(finished=True)
def solve_navier_stokes(conf, options): opts = conf.options dpb = ProblemDefinition.from_conf(conf, init_equations=False) equations = getattr(conf, "_".join(("equations_direct", opts.problem))) dpb.set_equations(equations) ls_conf = dpb.get_solver_conf(opts.ls) nls_conf = dpb.get_solver_conf(opts.nls_direct) method = opts.direct_method if method == "stationary": data = {} dpb.time_update(None) state_dp = dpb.solve(nls_conf=nls_conf) elif method == "transient": ls = Solver.any_from_conf(ls_conf) ts_conf = dpb.get_solver_conf(opts.ts_direct) data = {"ts": Struct(dt=ts_conf.dt)} # Plug in mass term. mequations = {} for key, eq in equations.iteritems(): if "dw_div_grad" in eq: eq = "+".join((ts_conf.mass_term, eq)).replace("++", "+") mequations[key] = eq if ts_conf.stokes_init: state_dp0 = solve_stokes(dpb, conf.equations_direct_stokes, nls_conf) dpb.set_equations(mequations) else: dpb.set_equations(mequations) state_dp0 = dpb.create_state() dpb.time_update(None) state_dp0.apply_ebc() from sfepy.base.log import Log log = Log.from_conf(Struct(is_plot=True), ([r"$||u||$"], [r"$||p||$"])) output("Navier-Stokes...") ev = BasicEvaluator(dpb, ts=Struct(dt=ts_conf.dt)) nls = Solver.any_from_conf(nls_conf, evaluator=ev, lin_solver=ls) n_step = ts_conf.n_step step = 0 while 1: for ii in xrange(n_step): output(step) vec_u = state_dp0("w") vec_p = state_dp0("r") log(nm.linalg.norm(vec_u), nm.linalg.norm(vec_p)) dpb.variables.set_data_from_state("w_0", state_dp0(), "w") vec_dp = nls(state_dp0()) step += 1 state_dp = state_dp0.copy() state_dp.set_reduced(vec_dp) state_dp0 = state_dp if ts_conf.interactive: try: n_step = int(raw_input("continue: ")) if n_step <= 0: break except: break vec_u = state_dp("w") vec_p = state_dp("r") log(nm.linalg.norm(vec_u), nm.linalg.norm(vec_p), finished=True) else: raise "unknown Navier-Stokes solution method (%s)!" % method return dpb, state_dp, data
class FMinSteepestDescent( OptimizationSolver ): name = 'opt.fmin_sd' def process_conf( conf ): """ Missing items are set to default values. Example configuration, all items:: solver_0 = { 'name' : 'fmin_sd', 'kind' : 'opt.fmin_sd', 'i_max' : 10, 'eps_rd' : 1e-5, # Relative delta of objective function 'eps_of' : 1e-4, 'eps_ofg' : 1e-8, 'norm' : nm.Inf, 'ls' : True, # Linesearch. 'ls_method' : 'backtracking', # 'backtracking' or 'full' 'ls0' : 0.25, 'ls_red' : 0.5, 'ls_red_warp' : 0.1, 'ls_on' : 0.99999, 'ls_min' : 1e-5, 'check' : 0, 'delta' : 1e-6, 'output' : None, # 'itc' 'log' : {'text' : 'output/log.txt', 'plot' : 'output/log.png'}, 'yscales' : ['linear', 'log', 'log', 'linear'], } """ get = conf.get_default_attr i_max = get( 'i_max', 10 ) eps_rd = get( 'eps_rd', 1e-5 ) eps_of = get( 'eps_of', 1e-4 ) eps_ofg = get( 'eps_ofg', 1e-8 ) norm = get( 'norm', nm.Inf ) ls = get( 'ls', True ) ls_method = get( 'ls_method', 'backtracking' ) ls0 = get( 'ls0', 0.25 ) ls_red = get( 'ls_red', 0.5 ) ls_red_warp = get( 'ls_red_warp', 0.1 ) ls_on = get( 'ls_on', 0.99999 ) ls_min = get( 'ls_min', 1e-5 ) check = get( 'check', 0 ) delta = get( 'delta', 1e-6) output = get( 'output', None ) yscales = get( 'yscales', ['linear', 'log', 'log', 'linear'] ) log = get_logging_conf(conf) log = Struct(name='log_conf', **log) is_any_log = (log.text is not None) or (log.plot is not None) common = OptimizationSolver.process_conf( conf ) return Struct( **locals() ) + common process_conf = staticmethod( process_conf ) ## # 17.10.2007, c def __init__( self, conf, **kwargs ): OptimizationSolver.__init__( self, conf, **kwargs ) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||\Psi||$'], [r'$||\nabla \Psi||$'], [r'$\alpha$'], ['iteration']], xlabels=['', '', 'all iterations', 'all iterations'], yscales=conf.yscales, is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%.3e'], ['%.3e'], ['%d']]) else: self.log = None ## # 19.04.2006, c # 20.04.2006 # 21.04.2006 # 26.04.2006 # 06.06.2006 # 07.06.2006 # 04.09.2006 # 21.03.2007 # 17.10.2007, from fmin_sd() def __call__( self, x0, conf = None, obj_fun = None, obj_fun_grad = None, status = None, obj_args = None ): # def fmin_sd( conf, x0, fn_of, fn_ofg, args = () ): 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 ) 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: tt = time.clock() check_gradient( xit, ofg, fn_of, conf.delta, conf.check ) time_stats['check'].append( time.clock() - tt ) 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 time_stats.iteritems(): 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
class Newton(NonlinearSolver): r""" Solves a nonlinear system :math:`f(x) = 0` using the Newton method with backtracking line-search, starting with an initial guess :math:`x^0`. """ name = 'nls.newton' __metaclass__ = SolverMeta _parameters = [ ('i_max', 'int', 1, False, 'The maximum number of iterations.'), ('eps_a', 'float', 1e-10, False, 'The absolute tolerance for the residual, i.e. :math:`||f(x^i)||`.'), ('eps_r', 'float', 1.0, False, """The relative tolerance for the residual, i.e. :math:`||f(x^i)|| / ||f(x^0)||`."""), ('eps_mode', "'and' or 'or'", 'and', False, """The logical operator to use for combining the absolute and relative tolerances."""), ('macheps', 'float', nm.finfo(nm.float64).eps, False, 'The float considered to be machine "zero".'), ('lin_red', 'float', 1.0, False, """The linear system solution error should be smaller than (`eps_a` * `lin_red`), otherwise a warning is printed."""), ('lin_precision', 'float or None', None, False, """If not None, the linear system solution tolerances are set in each nonlinear iteration relative to the current residual norm by the `lin_precision` factor. Ignored for direct linear solvers."""), ('ls_on', 'float', 0.99999, False, """Start the backtracking line-search by reducing the step, if :math:`||f(x^i)|| / ||f(x^{i-1})||` is larger than `ls_on`."""), ('ls_red', '0.0 < float < 1.0', 0.1, False, 'The step reduction factor in case of correct residual assembling.'), ('ls_red_warp', '0.0 < float < 1.0', 0.001, False, """The step reduction factor in case of failed residual assembling (e.g. the "warp violation" error caused by a negative volume element resulting from too large deformations)."""), ('ls_min', '0.0 < float < 1.0', 1e-5, False, 'The minimum step reduction factor.'), ('give_up_warp', 'bool', False, False, 'If True, abort on the "warp violation" error.'), ('check', '0, 1 or 2', 0, False, """If >= 1, check the tangent matrix using finite differences. If 2, plot the resulting sparsity patterns."""), ('delta', 'float', 1e-6, False, r"""If `check >= 1`, the finite difference matrix is taken as :math:`A_{ij} = \frac{f_i(x_j + \delta) - f_i(x_j - \delta)}{2 \delta}`."""), ('log', 'dict or None', None, False, """If not None, log the convergence according to the configuration in the following form: ``{'text' : 'log.txt', 'plot' : 'log.pdf'}``. Each of the dict items can be None."""), ('is_linear', 'bool', False, False, 'If True, the problem is considered to be linear.'), ] def __init__(self, conf, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration']], xlabels=['', 'all iterations'], ylabels=[r'$||r||$', 'iteration'], yscales=['log', 'linear'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d']]) else: self.log = None 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_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: 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['residual'] = 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('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 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 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
class Newton(NonlinearSolver): name = "nls.newton" @staticmethod def process_conf(conf, kwargs): """ Missing items are set to default values for a linear problem. Example configuration, all items:: solver_1 = { 'name' : 'newton', 'kind' : 'nls.newton', 'i_max' : 2, 'eps_a' : 1e-8, 'eps_r' : 1e-2, 'macheps' : 1e-16, 'lin_red' : 1e-2, # Linear system error < (eps_a * lin_red). 'lin_precision' : None, 'ls_red' : 0.1, 'ls_red_warp' : 0.001, 'ls_on' : 0.99999, 'ls_min' : 1e-5, 'give_up_warp' : False, 'check' : 0, 'delta' : 1e-6, 'is_plot' : False, 'log' : None, # 'nonlinear' or 'linear' (ignore i_max) 'problem' : 'nonlinear', } """ get = make_get_conf(conf, kwargs) common = NonlinearSolver.process_conf(conf) log = get_logging_conf(conf) log = Struct(name="log_conf", **log) is_any_log = (log.text is not None) or (log.plot is not None) return ( Struct( i_max=get("i_max", 1), eps_a=get("eps_a", 1e-10), eps_r=get("eps_r", 1.0), macheps=get("macheps", nm.finfo(nm.float64).eps), lin_red=get("lin_red", 1.0), lin_precision=get("lin_precision", None), ls_red=get("ls_red", 0.1), ls_red_warp=get("ls_red_warp", 0.001), ls_on=get("ls_on", 0.99999), ls_min=get("ls_min", 1e-5), give_up_warp=get("give_up_warp", False), check=get("check", 0), delta=get("delta", 1e-6), is_plot=get("is_plot", False), problem=get("problem", "nonlinear"), log=log, is_any_log=is_any_log, ) + common ) def __init__(self, conf, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf if conf.is_any_log: self.log = Log( [[r"$||r||$"], ["iteration"]], xlabels=["", "all iterations"], ylabels=[r"$||r||$", "iteration"], yscales=["log", "linear"], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[["%.8e"], ["%d"]], ) else: self.log = None 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 :math:`f(x) = 0` by the Newton method with backtracking linesearch. 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 1 iteration and no rezidual check! """ 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
class Oseen(NonlinearSolver): """ The Oseen solver for Navier-Stokes equations. """ name = 'nls.oseen' __metaclass__ = SolverMeta _parameters = [ ('stabil_mat', 'str', None, True, 'The name of stabilization material.'), ('adimensionalize', 'bool', False, False, 'If True, adimensionalize the problem (not implemented!).'), ('check_navier_stokes_rezidual', 'bool', False, False, 'If True, check the Navier-Stokes rezidual after the nonlinear loop.'), ('i_max', 'int', 1, False, 'The maximum number of iterations.'), ('eps_a', 'float', 1e-10, False, 'The absolute tolerance for the residual, i.e. :math:`||f(x^i)||`.'), ('eps_r', 'float', 1.0, False, """The relative tolerance for the residual, i.e. :math:`||f(x^i)|| / ||f(x^0)||`."""), ('macheps', 'float', nm.finfo(nm.float64).eps, False, 'The float considered to be machine "zero".'), ('lin_red', 'float', 1.0, False, """The linear system solution error should be smaller than (`eps_a` * `lin_red`), otherwise a warning is printed."""), ('lin_precision', 'float or None', None, False, """If not None, the linear system solution tolerances are set in each nonlinear iteration relative to the current residual norm by the `lin_precision` factor. Ignored for direct linear solvers."""), ] def __init__(self, conf, problem, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) conf.problem = problem conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration'], [r'$\gamma$', r'$\max(\delta)$', r'$\max(\tau)$']], xlabels=['', '', 'all iterations'], ylabels=[r'$||r||$', 'iteration', 'stabilization'], yscales=['log', 'linear', 'log'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d'], ['%.8e', '%.8e', '%.8e']]) else: self.log = None 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!') time_stats = {} stabil = problem.get_materials()[conf.stabil_mat] ns, ii = stabil.function.function.get_maps() variables = problem.get_variables() update_var = variables.set_data_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 tt = time.clock() try: vec_r = fun(vec_x) except ValueError: ok = False else: ok = True time_stats['rezidual'] = time.clock() - tt if ok: err = nla.norm(vec_r) if it == 0: err0 = err; else: err += nla.norm(vec_dx) else: # Failure. output('rezidual 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 tt = time.clock() try: mtx_a = fun_grad(vec_x) except ValueError: ok = False else: ok = True time_stats['matrix'] = time.clock() - tt if not ok: raise RuntimeError('giving up...') tt = time.clock() vec_dx = lin_solver(vec_r, x0=vec_x, mtx=mtx_a) time_stats['solve'] = time.clock() - tt 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_rezidual: 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 rezidual computation failed!') err_ns = err_ns0 = None else: err_ns0 = nla.norm(vec_rns0) err_ns = nla.norm(vec_rns) output('Navier-Stokes rezidual0: %.8e' % err_ns0) output('Navier-Stokes rezidual : %.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
class FMinSteepestDescent(OptimizationSolver): """ Steepest descent optimization solver. """ name = 'opt.fmin_sd' __metaclass__ = SolverMeta _parameters = [ ('i_max', 'int', 10, False, 'The maximum number of iterations.'), ('eps_rd', 'float', 1e-5, False, 'The relative delta of the objective function.'), ('eps_of', 'float', 1e-4, False, 'The tolerance for the objective function.'), ('eps_ofg', 'float', 1e-8, False, 'The tolerance for the objective function gradient.'), ('norm', 'numpy norm', nm.Inf, False, 'The norm to be used.'), ('ls', 'bool', True, False, 'If True, use a line-search.'), ('ls_method', "{'backtracking', 'full'}", 'backtracking', False, 'The line-search method.'), ('ls_on', 'float', 0.99999, False, """Start the backtracking line-search by reducing the step, if :math:`||f(x^i)|| / ||f(x^{i-1})||` is larger than `ls_on`."""), ('ls0', '0.0 < float < 1.0', 1.0, False, 'The initial step.'), ('ls_red', '0.0 < float < 1.0', 0.5, False, 'The step reduction factor in case of correct residual assembling.'), ('ls_red_warp', '0.0 < float < 1.0', 0.1, False, """The step reduction factor in case of failed residual assembling (e.g. the "warp violation" error caused by a negative volume element resulting from too large deformations)."""), ('ls_min', '0.0 < float < 1.0', 1e-5, False, 'The minimum step reduction factor.'), ('check', '0, 1 or 2', 0, False, """If >= 1, check the tangent matrix using finite differences. If 2, plot the resulting sparsity patterns."""), ('delta', 'float', 1e-6, False, r"""If `check >= 1`, the finite difference matrix is taken as :math:`A_{ij} = \frac{f_i(x_j + \delta) - f_i(x_j - \delta)}{2 \delta}`."""), ('output', 'function', None, False, """If given, use it instead of :func:`output() <sfepy.base.base.output()>` function."""), ('yscales', 'list of str', ['linear', 'log', 'log', 'linear'], False, 'The list of four convergence log subplot scales.'), ('log', 'dict or None', None, False, """If not None, log the convergence according to the configuration in the following form: ``{'text' : 'log.txt', 'plot' : 'log.pdf'}``. Each of the dict items can be None."""), ] def __init__(self, conf, **kwargs): OptimizationSolver.__init__(self, conf, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) if conf.is_any_log: self.log = Log( [[r'$||\Psi||$'], [r'$||\nabla \Psi||$'], [r'$\alpha$'], ['iteration']], xlabels=['', '', 'all iterations', 'all iterations'], yscales=conf.yscales, is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%.3e'], ['%.3e'], ['%d']]) else: self.log = None 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) 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: tt = time.clock() check_gradient(xit, ofg, fn_of, conf.delta, conf.check) time_stats['check'].append(time.clock() - tt) 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 time_stats.iteritems(): 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 solve_navier_stokes(conf, options): opts = conf.options dpb = Problem.from_conf(conf, init_equations=False) equations = getattr(conf, '_'.join(('equations_direct', opts.problem))) dpb.set_equations(equations) ls_conf = dpb.get_solver_conf(opts.ls) nls_conf = dpb.get_solver_conf(opts.nls_direct) method = opts.direct_method if method == 'stationary': data = {} dpb.time_update(None) state_dp = dpb.solve(nls_conf=nls_conf) elif method == 'transient': ls = Solver.any_from_conf(ls_conf) ts_conf = dpb.get_solver_conf(opts.ts_direct) data = {'ts': Struct(dt=ts_conf.dt)} # Plug in mass term. mequations = {} for key, eq in equations.iteritems(): if 'dw_div_grad' in eq: eq = '+'.join((ts_conf.mass_term, eq)).replace('++', '+') mequations[key] = eq if ts_conf.stokes_init: state_dp0 = solve_stokes(dpb, conf.equations_direct_stokes, nls_conf) dpb.set_equations(mequations) else: dpb.set_equations(mequations) state_dp0 = dpb.create_state() dpb.time_update(None) state_dp0.apply_ebc() from sfepy.base.log import Log log = Log.from_conf(Struct(is_plot=True), ([r'$||u||$'], [r'$||p||$'])) output('Navier-Stokes...') ev = BasicEvaluator(dpb, ts=Struct(dt=ts_conf.dt)) nls = Solver.any_from_conf(nls_conf, evaluator=ev, lin_solver=ls) n_step = ts_conf.n_step step = 0 while 1: for ii in xrange(n_step): output(step) vec_u = state_dp0('w') vec_p = state_dp0('r') log(nm.linalg.norm(vec_u), nm.linalg.norm(vec_p)) dpb.variables.set_data_from_state('w_0', state_dp0(), 'w') vec_dp = nls(state_dp0()) step += 1 state_dp = state_dp0.copy() state_dp.set_reduced(vec_dp) state_dp0 = state_dp if ts_conf.interactive: try: n_step = int(raw_input('continue: ')) if n_step <= 0: break except: break vec_u = state_dp('w') vec_p = state_dp('r') log(nm.linalg.norm(vec_u), nm.linalg.norm(vec_p), finished=True) else: raise 'unknown Navier-Stokes solution method (%s)!' % method return dpb, state_dp, data
class Oseen(NonlinearSolver): """ The Oseen solver for Navier-Stokes equations. """ name = 'nls.oseen' _parameters = [ ('stabil_mat', 'str', None, True, 'The name of stabilization material.'), ('adimensionalize', 'bool', False, False, 'If True, adimensionalize the problem (not implemented!).'), ('check_navier_stokes_residual', 'bool', False, False, 'If True, check the Navier-Stokes residual after the nonlinear loop.' ), ('i_max', 'int', 1, False, 'The maximum number of iterations.'), ('eps_a', 'float', 1e-10, False, 'The absolute tolerance for the residual, i.e. :math:`||f(x^i)||`.'), ('eps_r', 'float', 1.0, False, """The relative tolerance for the residual, i.e. :math:`||f(x^i)|| / ||f(x^0)||`."""), ('macheps', 'float', nm.finfo(nm.float64).eps, False, 'The float considered to be machine "zero".'), ('lin_red', 'float', 1.0, False, """The linear system solution error should be smaller than (`eps_a` * `lin_red`), otherwise a warning is printed."""), ('lin_precision', 'float or None', None, False, """If not None, the linear system solution tolerances are set in each nonlinear iteration relative to the current residual norm by the `lin_precision` factor. Ignored for direct linear solvers."""), ] def __init__(self, conf, context=None, **kwargs): NonlinearSolver.__init__(self, conf, context=context, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) conf.problem = context conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration'], [r'$\gamma$', r'$\max(\delta)$', r'$\max(\tau)$']], xlabels=['', '', 'all iterations'], ylabels=[r'$||r||$', 'iteration', 'stabilization'], yscales=['log', 'linear', 'log'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d'], ['%.8e', '%.8e', '%.8e']]) else: self.log = None 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
class Newton(NonlinearSolver): r""" Solves a nonlinear system :math:`f(x) = 0` using the Newton method with backtracking line-search, starting with an initial guess :math:`x^0`. For common configuration parameters, see :class:`Solver <sfepy.solvers.solvers.Solver>`. Parameters ---------- i_max : int The maximum number of iterations. eps_a : float The absolute tolerance for the residual, i.e. :math:`||f(x^i)||`. eps_r : float The relative tolerance for the residual, i.e. :math:`||f(x^i)|| / ||f(x^0)||`. macheps : float The float considered to be machine "zero". lin_red : float The linear system solution error should be smaller than (`eps_a` * `lin_red`), otherwise a warning is printed. lin_precision : float or None If not None, the linear system solution tolerances are set in each nonlinear iteration relative to the current residual norm by the `lin_precision` factor. Ignored for direct linear solvers. ls_on : float Start the backtracking line-search by reducing the step, if :math:`||f(x^i)|| / ||f(x^{i-1})||` is larger than `ls_on`. ls_red : 0.0 < float < 1.0 The step reduction factor in case of correct residual assembling. ls_red_warp : 0.0 < float < 1.0 The step reduction factor in case of failed residual assembling (e.g. the "warp violation" error caused by a negative volume element resulting from too large deformations). ls_min : 0.0 < float < 1.0 The minimum step reduction factor. give_up_warp : bool If True, abort on the "warp violation" error. check : 0, 1 or 2 If >= 1, check the tangent matrix using finite differences. If 2, plot the resulting sparsity patterns. delta : float If `check >= 1`, the finite difference matrix is taken as :math:`A_{ij} = \frac{f_i(x_j + \delta) - f_i(x_j - \delta)}{2 \delta}`. is_plot : False If True, plot the solution and residual in each step. log : dict or None If not None, log the convergence according to the configuration in the following form:: {'text' : 'log.txt', 'plot' : 'log.pdf'} Each of the dict items can be None. problem : 'nonlinear' or 'linear' Specifies if the problem is linear or non-linear. """ name = 'nls.newton' @staticmethod def process_conf(conf, kwargs): """ Missing items are set to default values for a linear problem. Example configuration, all items:: solver_1 = { 'name' : 'newton', 'kind' : 'nls.newton', 'i_max' : 2, 'eps_a' : 1e-8, 'eps_r' : 1e-2, 'macheps' : 1e-16, 'lin_red' : 1e-2, # Linear system error < (eps_a * lin_red). 'lin_precision' : None, 'ls_on' : 0.99999, 'ls_red' : 0.1, 'ls_red_warp' : 0.001, 'ls_min' : 1e-5, 'give_up_warp' : False, 'check' : 0, 'delta' : 1e-6, 'is_plot' : False, 'log' : None, # 'nonlinear' or 'linear' (ignore i_max) 'problem' : 'nonlinear', } """ get = make_get_conf(conf, kwargs) common = NonlinearSolver.process_conf(conf) log = get_logging_conf(conf) log = Struct(name='log_conf', **log) is_any_log = (log.text is not None) or (log.plot is not None) return Struct(i_max=get('i_max', 1), eps_a=get('eps_a', 1e-10), eps_r=get('eps_r', 1.0), macheps=get('macheps', nm.finfo(nm.float64).eps), lin_red=get('lin_red', 1.0), lin_precision=get('lin_precision', None), ls_red=get('ls_red', 0.1), ls_red_warp=get('ls_red_warp', 0.001), ls_on=get('ls_on', 0.99999), ls_min=get('ls_min', 1e-5), give_up_warp=get('give_up_warp', False), check=get('check', 0), delta=get('delta', 1e-6), is_plot=get('is_plot', False), problem=get('problem', 'nonlinear'), log=log, is_any_log=is_any_log) + common def __init__(self, conf, **kwargs): NonlinearSolver.__init__( self, conf, **kwargs ) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration']], xlabels=['', 'all iterations'], ylabels=[r'$||r||$', 'iteration'], yscales=['log', 'linear'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d']]) else: self.log = None 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 solve_navier_stokes(conf, options): opts = conf.options dpb = ProblemDefinition.from_conf(conf, init_equations=False) equations = getattr(conf, '_'.join(('equations_direct', opts.problem))) dpb.set_equations(equations) ls_conf = dpb.get_solver_conf( opts.ls ) nls_conf = dpb.get_solver_conf(opts.nls_direct) method = opts.direct_method if method == 'stationary': data = {} dpb.time_update(None) vec_dp = dpb.solve(nls_conf=nls_conf) elif method == 'transient': ls = Solver.any_from_conf( ls_conf ) ts_conf = dpb.get_solver_conf( opts.ts_direct ) data = {'ts' : Struct( dt = ts_conf.dt )} # Plug in mass term. mequations = {} for key, eq in equations.iteritems(): if 'dw_div_grad' in eq: eq = '+'.join( (ts_conf.mass_term, eq) ).replace( '++', '+') mequations[key] = eq if ts_conf.stokes_init: vec_dp0 = solve_stokes( dpb, conf.equations_direct_stokes, nls_conf ) dpb.set_equations( mequations ) else: dpb.set_equations( mequations ) vec_dp0 = dpb.create_state_vector() dpb.time_update( None ) dpb.apply_ebc( vec_dp0 ) from sfepy.base.log import Log log = Log.from_conf( Struct( is_plot = True ), ([r'$||u||$'], [r'$||p||$']) ) output( 'Navier-Stokes...' ) ev = BasicEvaluator( dpb, ts = Struct( dt = ts_conf.dt ) ) nls = Solver.any_from_conf( nls_conf, evaluator = ev, lin_solver = ls ) n_step = ts_conf.n_step step = 0 while 1: for ii in xrange( n_step ): output( step ) vec_u = dpb.variables.get_state_part_view( vec_dp0, 'w' ) vec_p = dpb.variables.get_state_part_view( vec_dp0, 'r' ) log( nm.linalg.norm( vec_u ), nm.linalg.norm( vec_p ) ) dpb.variables.non_state_data_from_state( 'w_0', vec_dp0, 'w' ) vec_dp = nls( vec_dp0 ) step += 1 vec_dp0 = vec_dp.copy() if ts_conf.interactive: try: n_step = int( raw_input( 'continue: ' ) ) if n_step <= 0: break except: break vec_u = dpb.variables.get_state_part_view( vec_dp, 'w' ) vec_p = dpb.variables.get_state_part_view( vec_dp, 'r' ) log( nm.linalg.norm( vec_u ), nm.linalg.norm( vec_p ), finished = True ) else: raise 'unknown Navier-Stokes solution method (%s)!' % method return dpb, vec_dp, data
class FMinSteepestDescent(OptimizationSolver): name = 'opt.fmin_sd' @staticmethod def process_conf(conf, kwargs): """ Missing items are set to default values. Example configuration, all items:: solver_0 = { 'name' : 'fmin_sd', 'kind' : 'opt.fmin_sd', 'i_max' : 10, 'eps_rd' : 1e-5, # Relative delta of objective function 'eps_of' : 1e-4, 'eps_ofg' : 1e-8, 'norm' : nm.Inf, 'ls' : True, # Linesearch. 'ls_method' : 'backtracking', # 'backtracking' or 'full' 'ls0' : 0.25, 'ls_red' : 0.5, 'ls_red_warp' : 0.1, 'ls_on' : 0.99999, 'ls_min' : 1e-5, 'check' : 0, 'delta' : 1e-6, 'output' : None, # 'itc' 'log' : {'text' : 'output/log.txt', 'plot' : 'output/log.png'}, 'yscales' : ['linear', 'log', 'log', 'linear'], } """ get = make_get_conf(conf, kwargs) common = OptimizationSolver.process_conf(conf) log = get_logging_conf(conf) log = Struct(name='log_conf', **log) is_any_log = (log.text is not None) or (log.plot is not None) return Struct(i_max=get('i_max', 10), eps_rd=get('eps_rd', 1e-5), eps_of=get('eps_of', 1e-4), eps_ofg=get('eps_ofg', 1e-8), norm=get('norm', nm.Inf), ls=get('ls', True), ls_method=get('ls_method', 'backtracking'), ls0=get('ls0', 0.25), ls_red=get('ls_red', 0.5), ls_red_warp=get('ls_red_warp', 0.1), ls_on=get('ls_on', 0.99999), ls_min=get('ls_min', 1e-5), check=get('check', 0), delta=get('delta', 1e-6), output=get('output', None), yscales=get('yscales', ['linear', 'log', 'log', 'linear']), log=log, is_any_log=is_any_log) + common ## # 17.10.2007, c def __init__(self, conf, **kwargs): OptimizationSolver.__init__(self, conf, **kwargs) conf = self.conf if conf.is_any_log: self.log = Log( [[r'$||\Psi||$'], [r'$||\nabla \Psi||$'], [r'$\alpha$'], ['iteration']], xlabels=['', '', 'all iterations', 'all iterations'], yscales=conf.yscales, is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%.3e'], ['%.3e'], ['%d']]) else: self.log = None ## # 19.04.2006, c # 20.04.2006 # 21.04.2006 # 26.04.2006 # 06.06.2006 # 07.06.2006 # 04.09.2006 # 21.03.2007 # 17.10.2007, from fmin_sd() def __call__(self, x0, conf=None, obj_fun=None, obj_fun_grad=None, status=None, obj_args=None): # def fmin_sd( conf, x0, fn_of, fn_ofg, args = () ): 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) 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: tt = time.clock() check_gradient(xit, ofg, fn_of, conf.delta, conf.check) time_stats['check'].append(time.clock() - tt) 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 time_stats.iteritems(): 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 solve_eigen_problem_n( self ): opts = self.app_options pb = self.problem dim = pb.domain.mesh.dim pb.set_equations( pb.conf.equations ) pb.select_bcs( ebc_names = ['ZeroSurface'] ) output( 'assembling rhs...' ) tt = time.clock() mtx_b = pb.evaluate(pb.conf.equations['rhs'], mode='weak', auto_init=True, dw_mode='matrix') output( '...done in %.2f s' % (time.clock() - tt) ) assert_( nm.alltrue( nm.isfinite( mtx_b.data ) ) ) ## mtx_b.save( 'b.txt', format='%d %d %.12f\n' ) aux = pb.create_evaluable(pb.conf.equations['lhs'], mode='weak', dw_mode='matrix') mtx_a_equations, mtx_a_variables = aux if self.options.plot: log_conf = { 'is_plot' : True, 'aggregate' : 1, 'yscales' : ['linear', 'log'], } else: log_conf = { 'is_plot' : False, } log = Log.from_conf( log_conf, ([r'$|F(x)|$'], [r'$|F(x)-x|$']) ) file_output = Output('', opts.log_filename, combined = True) eig_conf = pb.get_solver_conf( opts.eigen_solver ) eig_solver = Solver.any_from_conf( eig_conf ) # Just to get the shape. Assumes one element group only!!! v_hxc_qp = pb.evaluate('dq_state_in_volume_qp.i1.Omega(Psi)') v_hxc_qp.fill(0.0) self.qp_shape = v_hxc_qp.shape vec_v_hxc = self._interp_to_nodes(v_hxc_qp) self.norm_v_hxc0 = nla.norm(vec_v_hxc) self.itercount = 0 aux = wrap_function(self.iterate, (eig_solver, mtx_a_equations, mtx_a_variables, mtx_b, log, file_output)) ncalls, times, nonlin_v, results = aux # Create and call the DFT solver. dft_conf = pb.get_solver_conf(opts.dft_solver) dft_status = {} dft_solver = Solver.any_from_conf(dft_conf, fun = nonlin_v, status = dft_status) v_hxc_qp = dft_solver(v_hxc_qp.ravel()) v_hxc_qp = nm.array(v_hxc_qp, dtype=nm.float64) v_hxc_qp.shape = self.qp_shape eigs, mtx_s_phi, vec_n, vec_v_h, v_ion_qp, v_xc_qp, v_hxc_qp = results output( 'DFT iteration time [s]:', dft_status['time_stats'] ) fun = pb.materials['mat_v'].function variable = self.problem.create_variables(['scalar'])['scalar'] vec_v_ion = fun(None, variable.field.get_coor(), mode='qp')['V_ion'].squeeze() vec_v_xc = self._interp_to_nodes(v_xc_qp) vec_v_hxc = self._interp_to_nodes(v_hxc_qp) vec_v_sum = self._interp_to_nodes(v_hxc_qp + v_ion_qp) coor = pb.domain.get_mesh_coors() r2 = norm_l2_along_axis(coor, squared=True) vec_nr2 = vec_n * r2 pb.select_bcs( ebc_names = ['ZeroSurface'] ) mtx_phi = self.make_full( mtx_s_phi ) out = {} update_state_to_output(out, pb, vec_n, 'n') update_state_to_output(out, pb, vec_nr2, 'nr2') update_state_to_output(out, pb, vec_v_h, 'V_h') update_state_to_output(out, pb, vec_v_xc, 'V_xc') update_state_to_output(out, pb, vec_v_ion, 'V_ion') update_state_to_output(out, pb, vec_v_hxc, 'V_hxc') update_state_to_output(out, pb, vec_v_sum, 'V_sum') self.save_results(eigs, mtx_phi, out=out) if self.options.plot: log( save_figure = opts.iter_fig_name ) pause() log(finished=True) return Struct( pb = pb, eigs = eigs, mtx_phi = mtx_phi, vec_n = vec_n, vec_nr2 = vec_nr2, vec_v_h = vec_v_h, vec_v_xc = vec_v_xc )
class Oseen(NonlinearSolver): name = 'nls.oseen' @staticmethod def process_conf(conf, kwargs): """ Missing items are set to default values. Example configuration, all items:: solver_1 = { 'name' : 'oseen', 'kind' : 'nls.oseen', 'needs_problem_instance' : True, 'stabil_mat' : 'stabil', 'adimensionalize' : False, 'check_navier_stokes_rezidual' : False, 'i_max' : 10, 'eps_a' : 1e-8, 'eps_r' : 1.0, 'macheps' : 1e-16, 'lin_red' : 1e-2, # Linear system error < (eps_a * lin_red). 'log' : {'text' : 'oseen_log.txt', 'plot' : 'oseen_log.png'}, } """ get = make_get_conf(conf, kwargs) common = NonlinearSolver.process_conf(conf) # Compulsory. needs_problem_instance = get('needs_problem_instance', True) if not needs_problem_instance: msg = 'set solver option "needs_problem_instance" to True!' raise ValueError(msg) stabil_mat = get('stabil_mat', None, 'missing "stabil_mat" in options!') # With defaults. adimensionalize = get('adimensionalize', False) if adimensionalize: raise NotImplementedError check = get('check_navier_stokes_rezidual', False) log = get_logging_conf(conf) log = Struct(name='log_conf', **log) is_any_log = (log.text is not None) or (log.plot is not None) return Struct(needs_problem_instance=needs_problem_instance, stabil_mat=stabil_mat, adimensionalize=adimensionalize, check_navier_stokes_rezidual=check, i_max=get('i_max', 1), eps_a=get('eps_a', 1e-10), eps_r=get('eps_r', 1.0), macheps=get('macheps', nm.finfo(nm.float64).eps), lin_red=get('lin_red', 1.0), lin_precision=get('lin_precision', None), log=log, is_any_log=is_any_log) + common def __init__(self, conf, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration'], [r'$\gamma$', r'$\max(\delta)$', r'$\max(\tau)$']], xlabels=['', '', 'all iterations'], ylabels=[r'$||r||$', 'iteration', 'stabilization'], yscales=['log', 'linear', 'log'], log_filename=conf.log.text, formats=[['%.8e'], ['%d'], ['%.8e', '%.8e', '%.8e']]) else: self.log = None 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, self.problem) if problem is None: msg = 'set solver option "needs_problem_instance" to True!' raise ValueError(msg) time_stats = {} stabil = problem.get_materials()[conf.stabil_mat] ns, ii = stabil.function.function.get_maps() variables = problem.get_variables() update_var = variables.set_data_from_state make_full_vec = variables.make_full_vec print 'problem size:' print ' velocity: %s' % ii['us'] print ' 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) print '|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) print '|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())) print 'stabilization parameters:' print ' gamma: %.12e' % max_pars[ns['gamma']] print ' max( delta ): %.12e' % max_pars[ns['delta']] print ' max( tau ): %.12e' % max_pars[ns['tau']] if (not are_close(b_norm, 1.0)) and conf.adimensionalize: adimensionalize = True else: adimensionalize = False tt = time.clock() try: vec_r = fun(vec_x) except ValueError: ok = False else: ok = True time_stats['rezidual'] = time.clock() - tt if ok: err = nla.norm(vec_r) if it == 0: err0 = err else: err += nla.norm(vec_dx) else: # Failure. output('rezidual 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 tt = time.clock() try: mtx_a = fun_grad(vec_x) except ValueError: ok = False else: ok = True time_stats['matrix'] = time.clock() - tt if not ok: raise RuntimeError('giving up...') tt = time.clock() vec_dx = lin_solver(vec_r, x0=vec_x, mtx=mtx_a) time_stats['solve'] = time.clock() - tt 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 time_stats.iteritems(): output('%10s: %7.2f [s]' % kv) vec_x_prev = vec_x.copy() vec_x -= vec_dx it += 1 if conf.check_navier_stokes_rezidual: 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: print 'Navier-Stokes rezidual computation failed!' err_ns = err_ns0 = None else: err_ns0 = nla.norm(vec_rns0) err_ns = nla.norm(vec_rns) print 'Navier-Stokes rezidual0: %.8e' % err_ns0 print 'Navier-Stokes rezidual : %.8e' % err_ns print 'b - u: %.8e' % nla.norm(vec_b - vec_u) print 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
class Newton( NonlinearSolver ): name = 'nls.newton' def process_conf( conf ): """ Missing items are set to default values for a linear problem. Example configuration, all items:: solver_1 = { 'name' : 'newton', 'kind' : 'nls.newton', 'i_max' : 2, 'eps_a' : 1e-8, 'eps_r' : 1e-2, 'macheps' : 1e-16, 'lin_red' : 1e-2, # Linear system error < (eps_a * lin_red). 'ls_red' : 0.1, 'ls_red_warp' : 0.001, 'ls_on' : 0.99999, 'ls_min' : 1e-5, 'check' : 0, 'delta' : 1e-6, 'is_plot' : False, 'log' : None, # 'nonlinear' or 'linear' (ignore i_max) 'problem' : 'nonlinear', } """ get = conf.get_default_attr i_max = get( 'i_max', 1 ) eps_a = get( 'eps_a', 1e-10 ) eps_r = get( 'eps_r', 1.0 ) macheps = get( 'macheps', nm.finfo( nm.float64 ).eps ) lin_red = get( 'lin_red', 1.0 ) ls_red = get( 'ls_red', 0.1 ) ls_red_warp = get( 'ls_red_warp', 0.001 ) ls_on = get( 'ls_on', 0.99999 ) ls_min = get( 'ls_min', 1e-5 ) check = get( 'check', 0 ) delta = get( 'delta', 1e-6) is_plot = get( 'is_plot', False ) problem = get( 'problem', 'nonlinear' ) log = get_logging_conf(conf) log = Struct(name='log_conf', **log) is_any_log = (log.text is not None) or (log.plot is not None) common = NonlinearSolver.process_conf( conf ) return Struct( **locals() ) + common process_conf = staticmethod( process_conf ) def __init__(self, conf, **kwargs): NonlinearSolver.__init__( self, conf, **kwargs ) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration']], xlabels=['', 'all iterations'], ylabels=[r'$||r||$', 'iteration'], yscales=['log', 'linear'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d']]) else: self.log = None ## # c: 02.12.2005, r: 04.04.2008 # 10.10.2007, from newton() def __call__( self, vec_x0, conf = None, fun = None, fun_grad = None, lin_solver = None, status = None ): """setting conf.problem == 'linear' means 1 iteration and no rezidual check! """ 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 ) 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 while 1: 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 = 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. 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 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 tt = time.clock() vec_dx = lin_solver( vec_r, mtx = mtx_a ) time_stats['solve'] = time.clock() - tt 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 > (conf.eps_a * conf.lin_red): output( 'linear system not solved! (err = %e)' % lerr ) vec_x -= vec_dx if conf.is_plot: plu.pylab.ion() plu.pylab.gcf().clear() plu.pylab.subplot( 2, 2, 1 ) plu.pylab.plot( vec_x_last ) plu.pylab.ylabel( r'$x_{i-1}$' ) plu.pylab.subplot( 2, 2, 2 ) plu.pylab.plot( vec_r ) plu.pylab.ylabel( r'$r$' ) plu.pylab.subplot( 2, 2, 4 ) plu.pylab.plot( vec_dx ) plu.pylab.ylabel( r'$\_delta x$' ) plu.pylab.subplot( 2, 2, 3 ) plu.pylab.plot( vec_x ) plu.pylab.ylabel( r'$x_i$' ) plu.pylab.draw() plu.pylab.ioff() pause() 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(): # Aluminium and epoxy. default_pars = '70e9,0.35,2.799e3, 3.8e9,0.27,1.142e3' default_solver_conf = ("kind='eig.scipy',method='eigsh',tol=1.0e-5," "maxiter=1000,which='LM',sigma=0.0") parser = ArgumentParser(description=__doc__, formatter_class=RawDescriptionHelpFormatter) parser.add_argument('--pars', metavar='young1,poisson1,density1' ',young2,poisson2,density2', action='store', dest='pars', default=default_pars, help=helps['pars']) parser.add_argument('--conf', metavar='filename', action='store', dest='conf', default=None, help=helps['conf']) parser.add_argument('--define-kwargs', metavar='dict-like', action='store', dest='define_kwargs', default=None, help=helps['define_kwargs']) parser.add_argument('--mesh-size', type=float, metavar='float', action='store', dest='mesh_size', default=None, help=helps['mesh_size']) parser.add_argument('--unit-multipliers', metavar='c_time,c_length,c_mass', action='store', dest='unit_multipliers', default='1.0,1.0,1.0', help=helps['unit_multipliers']) parser.add_argument('--plane', action='store', dest='plane', choices=['strain', 'stress'], default='strain', help=helps['plane']) parser.add_argument('--wave-dir', metavar='float,float[,float]', action='store', dest='wave_dir', default='1.0,0.0,0.0', help=helps['wave_dir']) parser.add_argument('--mode', action='store', dest='mode', choices=['omega', 'kappa'], default='omega', help=helps['mode']) parser.add_argument('--stepper', action='store', dest='stepper', choices=['linear', 'brillouin'], default='linear', help=helps['stepper']) parser.add_argument('--range', metavar='start,stop,count', action='store', dest='range', default='0,6.4,33', help=helps['range']) parser.add_argument('--order', metavar='int', type=int, action='store', dest='order', default=1, help=helps['order']) parser.add_argument('--refine', metavar='int', type=int, action='store', dest='refine', default=0, help=helps['refine']) parser.add_argument('-n', '--n-eigs', metavar='int', type=int, action='store', dest='n_eigs', default=6, help=helps['n_eigs']) group = parser.add_mutually_exclusive_group() group.add_argument('--eigs-only', action='store_true', dest='eigs_only', default=False, help=helps['eigs_only']) group.add_argument('--post-process', action='store_true', dest='post_process', default=False, help=helps['post_process']) parser.add_argument('--solver-conf', metavar='dict-like', action='store', dest='solver_conf', default=default_solver_conf, help=helps['solver_conf']) parser.add_argument('--save-regions', action='store_true', dest='save_regions', default=False, help=helps['save_regions']) parser.add_argument('--save-materials', action='store_true', dest='save_materials', default=False, help=helps['save_materials']) parser.add_argument('--log-std-waves', action='store_true', dest='log_std_waves', default=False, help=helps['log_std_waves']) parser.add_argument('--no-legends', action='store_false', dest='show_legends', default=True, help=helps['no_legends']) parser.add_argument('--no-show', action='store_false', dest='show', default=True, help=helps['no_show']) parser.add_argument('--silent', action='store_true', dest='silent', default=False, help=helps['silent']) parser.add_argument('-c', '--clear', action='store_true', dest='clear', default=False, help=helps['clear']) parser.add_argument('-o', '--output-dir', metavar='path', action='store', dest='output_dir', default='output', help=helps['output_dir']) parser.add_argument('mesh_filename', default='', help=helps['mesh_filename']) options = parser.parse_args() output_dir = options.output_dir output.set_output(filename=os.path.join(output_dir,'output_log.txt'), combined=options.silent == False) if options.conf is not None: mod = import_file(options.conf) else: mod = sys.modules[__name__] apply_units = mod.apply_units define = mod.define set_wave_dir = mod.set_wave_dir setup_n_eigs = mod.setup_n_eigs build_evp_matrices = mod.build_evp_matrices save_materials = mod.save_materials get_std_wave_fun = mod.get_std_wave_fun get_stepper = mod.get_stepper process_evp_results = mod.process_evp_results options.pars = [float(ii) for ii in options.pars.split(',')] options.unit_multipliers = [float(ii) for ii in options.unit_multipliers.split(',')] options.wave_dir = [float(ii) for ii in options.wave_dir.split(',')] aux = options.range.split(',') options.range = [float(aux[0]), float(aux[1]), int(aux[2])] options.solver_conf = dict_from_string(options.solver_conf) options.define_kwargs = dict_from_string(options.define_kwargs) if options.clear: remove_files_patterns(output_dir, ['*.h5', '*.vtk', '*.txt'], ignores=['output_log.txt'], verbose=True) filename = os.path.join(output_dir, 'options.txt') ensure_path(filename) save_options(filename, [('options', vars(options))], quote_command_line=True) pars = apply_units(options.pars, options.unit_multipliers) output('material parameters with applied unit multipliers:') output(pars) if options.mode == 'omega': rng = copy(options.range) rng[:2] = apply_unit_multipliers(options.range[:2], ['wave_number', 'wave_number'], options.unit_multipliers) output('wave number range with applied unit multipliers:', rng) else: if options.stepper == 'brillouin': raise ValueError('Cannot use "brillouin" stepper in kappa mode!') rng = copy(options.range) rng[:2] = apply_unit_multipliers(options.range[:2], ['frequency', 'frequency'], options.unit_multipliers) output('frequency range with applied unit multipliers:', rng) pb, wdir, bzone, mtxs = assemble_matrices(define, mod, pars, set_wave_dir, options) dim = pb.domain.shape.dim if dim != 2: options.plane = 'strain' if options.save_regions: pb.save_regions_as_groups(os.path.join(output_dir, 'regions')) if options.save_materials: save_materials(output_dir, pb, options) conf = pb.solver_confs['eig'] eig_solver = Solver.any_from_conf(conf) n_eigs, options.n_eigs = setup_n_eigs(options, pb, mtxs) get_color = lambda ii: plt.cm.viridis((float(ii) / (options.n_eigs - 1))) plot_kwargs = [{'color' : get_color(ii), 'ls' : '', 'marker' : 'o'} for ii in range(options.n_eigs)] get_color_dim = lambda ii: plt.cm.viridis((float(ii) / (dim-1))) plot_kwargs_dim = [{'color' : get_color_dim(ii), 'ls' : '', 'marker' : 'o'} for ii in range(dim)] log_names = [] log_plot_kwargs = [] if options.log_std_waves: std_wave_fun, log_names, log_plot_kwargs = get_std_wave_fun( pb, options) else: std_wave_fun = None stepper = get_stepper(rng, pb, options) if options.mode == 'omega': eigenshapes_filename = os.path.join(output_dir, 'frequency-eigenshapes-%s.vtk' % stepper.suffix) if options.stepper == 'linear': log = Log([[r'$\lambda_{%d}$' % ii for ii in range(options.n_eigs)], [r'$\omega_{%d}$' % ii for ii in range(options.n_eigs)] + log_names], plot_kwargs=[plot_kwargs, plot_kwargs + log_plot_kwargs], formats=[['{:.5e}'] * options.n_eigs, ['{:.5e}'] * (options.n_eigs + len(log_names))], yscales=['linear', 'linear'], xlabels=[r'$\kappa$', r'$\kappa$'], ylabels=[r'eigenvalues $\lambda_i$', r'frequencies $\omega_i$'], show_legends=options.show_legends, is_plot=options.show, log_filename=os.path.join(output_dir, 'frequencies.txt'), aggregate=1000, sleep=0.1) else: log = Log([[r'$\kappa_{%d}$'% ii for ii in range(dim)], [r'$\omega_{%d}$' % ii for ii in range(options.n_eigs)] + log_names], plot_kwargs=[plot_kwargs_dim, plot_kwargs + log_plot_kwargs], formats=[['{:.5e}'] * dim, ['{:.5e}'] * (options.n_eigs + len(log_names))], yscales=['linear', 'linear'], xlabels=[r'', r''], ylabels=[r'wave vector $\kappa$', r'frequencies $\omega_i$'], show_legends=options.show_legends, is_plot=options.show, log_filename=os.path.join(output_dir, 'frequencies.txt'), aggregate=1000, sleep=0.1) for aux in stepper: if options.stepper == 'linear': iv, wmag = aux else: iv, wmag, wdir = aux output('step %d: wave vector %s' % (iv, wmag * wdir)) if options.stepper == 'brillouin': pb, _, bzone, mtxs = assemble_matrices( define, mod, pars, set_wave_dir, options, wdir=wdir) evp_mtxs = build_evp_matrices(mtxs, wmag, options.mode, pb) if options.eigs_only: eigs = eig_solver(*evp_mtxs, n_eigs=n_eigs, eigenvectors=False) svecs = None else: eigs, svecs = eig_solver(*evp_mtxs, n_eigs=n_eigs, eigenvectors=True) omegas, svecs, out = process_evp_results( eigs, svecs, wmag, wdir, bzone, pb, mtxs, options, std_wave_fun=std_wave_fun ) if options.stepper == 'linear': log(*out, x=[wmag, wmag]) else: log(*out, x=[iv, iv]) save_eigenvectors(eigenshapes_filename % iv, svecs, wmag, wdir, pb) gc.collect() log(save_figure=os.path.join(output_dir, 'frequencies.png')) log(finished=True) else: eigenshapes_filename = os.path.join(output_dir, 'wave-number-eigenshapes-%s.vtk' % stepper.suffix) log = Log([[r'$\kappa_{%d}$' % ii for ii in range(options.n_eigs)] + log_names], plot_kwargs=[plot_kwargs + log_plot_kwargs], formats=[['{:.5e}'] * (options.n_eigs + len(log_names))], yscales=['linear'], xlabels=[r'$\omega$'], ylabels=[r'wave numbers $\kappa_i$'], show_legends=options.show_legends, is_plot=options.show, log_filename=os.path.join(output_dir, 'wave-numbers.txt'), aggregate=1000, sleep=0.1) for io, omega in stepper: output('step %d: frequency %s' % (io, omega)) evp_mtxs = build_evp_matrices(mtxs, omega, options.mode, pb) if options.eigs_only: eigs = eig_solver(*evp_mtxs, n_eigs=n_eigs, eigenvectors=False) svecs = None else: eigs, svecs = eig_solver(*evp_mtxs, n_eigs=n_eigs, eigenvectors=True) kappas, svecs, out = process_evp_results( eigs, svecs, omega, wdir, bzone, pb, mtxs, options, std_wave_fun=std_wave_fun ) log(*out, x=[omega]) save_eigenvectors(eigenshapes_filename % io, svecs, kappas, wdir, pb) gc.collect() log(save_figure=os.path.join(output_dir, 'wave-numbers.png')) log(finished=True)
def __call__(self, x0, conf=None, obj_fun=None, obj_fun_grad=None, status=None, obj_args=None): # def fmin_sd( conf, x0, fn_of, fn_ofg, args = () ): 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) time_stats = {"of": tt_of, "ofg": tt_ofg, "check": []} if conf.log: log = Log.from_conf(conf, ([r"of"], [r"$||$ofg$||$"], [r"alpha"])) else: log = None 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 = 1 ofg = fn_ofg(xit) if conf.check: tt = time.clock() check_gradient(xit, ofg, fn_of, conf.delta, conf.check) time_stats["check"].append(time.clock() - tt) 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 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 conf.log: log(of, ofg_norm, alpha) xit = xit - alpha * ofg if ofg1 is None: ofg = None else: ofg = ofg1.copy() for key, val in time_stats.iteritems(): 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 conf.log: log(of, ofg_norm, alpha, finished=True) if status is not None: status["log"] = 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