Source code for sfepy.solvers.oseen

import time

import numpy as nm
import numpy.linalg as nla

from sfepy.base.base import output, get_default, pause, Struct
from sfepy.base.log import Log, get_logging_conf
from sfepy.solvers.solvers import make_get_conf, NonlinearSolver
from nls import conv_test

[docs]class StabilizationFunction(Struct): """ Definition of stabilization material function for the Oseen solver. Notes ----- - tau_red <= 1.0; if tau is None: tau = tau_red * delta - diameter mode: 'edge': longest edge 'volume': volume-based, 'max': max. of previous """ def __init__(self, name_map, gamma=None, delta=None, tau=None, tau_red=1.0, tau_mul=1.0, delta_mul=1.0, gamma_mul=1.0, diameter_mode='max'): Struct.__init__(self, name_map=name_map, gamma=gamma, delta=delta, tau=tau, tau_red=tau_red, tau_mul=tau_mul, delta_mul=delta_mul, gamma_mul=gamma_mul, diameter_mode=diameter_mode)
[docs] def setup(self, problem): """ Setup common problem-dependent data. """ variables = problem.get_variables() ns = self.name_map # Indices to the state vector. ii = {} ii['u'] = variables.get_indx(ns['u']) ii['us'] = variables.get_indx(ns['u'], stripped=True) ii['ps'] = variables.get_indx(ns['p'], stripped=True) self.indices = ii materials = problem.get_materials() # The viscosity. fluid_mat = materials[ns['fluid']] self.viscosity = fluid_mat.function()[ns['viscosity']] # The Friedrich's constant. self.c_friedrichs = problem.domain.get_diameter() self.sigma = 1e-12 # 1 / dt. self.b_norm = 1.0
[docs] def get_maps(self): """ Get the maps of names and indices of variables in state vector. """ return self.name_map, self.indices
def __call__(self, ts, coor, mode=None, term=None, problem=None, b_norm=None, **kwargs): """ The actual material function. """ if mode != 'qp': return if not hasattr(self, 'viscosity'): self.setup(problem) ns = self.name_map # Update stored b_norm. self.b_norm = get_default(b_norm, self.b_norm) output('|b|_max (mat_fun):', self.b_norm) gamma = self.viscosity + self.b_norm * self.c_friedrichs data = {} if self.gamma is None: _gamma = self.gamma_mul * gamma else: _gamma = nm.asarray(self.gamma_mul * self.gamma, dtype=nm.float64) _gamma = nm.tile(_gamma, (coor.shape[0], 1, 1)) if self.delta is None: # Element diameter modes. dm = {'edge': 0, 'volume': 1, 'max': 2}[self.diameter_mode] field = problem.fields[ns['velocity']] region = term.region diameters2 = [] for ig in term.iter_groups(): vg, _ = field.get_mapping(ig, region, term.integral, 'volume') cells = region.get_cells(ig) d2 = problem.domain.get_element_diameters(ig, cells, vg, dm) diameters2.append(d2) self.diameters2 = nm.concatenate(diameters2) val1 = min(1.0, 1.0 / self.sigma) val2 = self.sigma * self.c_friedrichs**2 val3 = (self.b_norm**2) \ * min((self.c_friedrichs**2) / self.viscosity, 1.0 / self.sigma) n_qp = coor.shape[0] / self.diameters2.shape[0] diameters2 = nm.repeat(self.diameters2, n_qp) diameters2.shape = diameters2.shape + (1, 1) _delta = self.delta_mul * val1 * diameters2 / (_gamma + val2 + val3) else: val = nm.asarray(self.delta_mul * self.delta, dtype=nm.float64) _delta = nm.tile(val, (coor.shape[0], 1, 1)) if self.tau is None: _tau = self.tau_red * _delta else: _tau = nm.asarray(self.tau_mul * self.tau, dtype=nm.float64) _tau = nm.tile(_tau, (coor.shape[0], 1, 1)) data[ns['gamma']] = _gamma data[ns['delta']] = _delta data[ns['tau']] = _tau return data ## # 26.07.2007, c
[docs]def are_close( a, b, rtol = 0.2, atol = 1e-8 ): return False # return abs( a - b ) <= max( atol, rtol * abs( b ) ) ## # 26.07.2007, c
[docs]def scale_matrix( mtx, indx, factor ): ptr0 = mtx.indptr[indx.start] ptr1 = mtx.indptr[indx.stop] mtx.data[ptr0:ptr1] *= factor ## # 11.10.2007, c
[docs]class Oseen( NonlinearSolver ): name = 'nls.oseen' @staticmethod
[docs] 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 ProblemDefinition 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