def solve(self, *args, print_feval=True, **kwargs): feval = self._feval if 'init' not in kwargs: kwargs['init'] = self.init() # add an empty dict ``jac_options`` if it doesn't already exist kwargs.setdefault('jac_options', {}) # this value is chosen heuristically kwargs['jac_options'].setdefault('inner_atol', 1e-12) ret = root(self, *args, **kwargs) if print_feval: feval = self._feval - feval entries_computed = 2 * feval * self._N entries_jacobian = 8 * self.M.nnz log.info( 'Reached convergence after {} function evaluations.'.format( feval)) log.info( 'This corresponds to {} evaluations of the Jacobian.'.format( entries_computed / entries_jacobian)) # discard the auxilliary variables from the solution return ret[-len(self._g.dofindices):]
def newton(f, x0, maxiter, restol, lintol): '''find x such that f(x) = 0, starting at x0''' for i in log.range('newton', maxiter + 1): if i > 0: # solve system linearised around `x`, solution in `direction` J = f(x, jacobian=True) direction = -J.solve(residual, tol=lintol) xprev = x residual_norm_prev = residual_norm # line search, stop if there is convergence w.r.t. iteration `i-1` for j in range(4): x = xprev + (0.5)**j * direction residual = f(x) residual_norm = numpy.linalg.norm(residual, 2) if residual_norm < residual_norm_prev: break # else: no convergence, repeat and reduce step size by one half else: log.warning('divergence') else: # before first iteration, compute initial residual x = x0 residual = f(x) residual_norm = numpy.linalg.norm(residual, 2) log.info('residual norm: {:.5e}'.format(residual_norm)) if residual_norm < restol: break else: raise ValueError( 'newton did not converge in {} iterations'.format(maxiter)) return x
def residual(self, c): g11, g12, g22 = self.metric(c) ret = (self._weights * (g11**2 + 2 * g12**2 + g22**2)).sum() log.info(ret) return ret
def smoothen_vector(vec0, dt, method='finite_difference', stop={'T': 0.01}, miniter=10): """ Smoothen vec[1: -1] using `method' until stopping criterion has been reached, while vec[0] and vec[-1] are held fixed. Parameters ---------- vec0 : to-be-smoothened vector dt : (initial) timestep, is reduced if the convergence criterion is reached before #iterations >= ``miniter`` method : smoothing method stop = { 'T': (finite difference) if t > T, terminate 'maxiter': (finite difference) if i > maxiter, terminate 'vec': if not stop[ 'vec' ]( vec ) terminate } miniter : minimum number of iterations """ t, i = 0, 0 vec = vec0.copy() d = ChainMap(stop, {'T': np.inf, 'maxiter': 100, 'vec': lambda x: True}) if method == 'finite_difference': N = len(vec) dx = 1 / (N - 1) fac = dt / (dx**2) A = sparse.diags([(-fac * np.ones(N - 2)).tolist() + [0], [1] + ((1 + 2 * fac) * np.ones(N - 2)).tolist() + [1], [0] + (-fac * np.ones(N - 2)).tolist()], [-1, 0, 1]).tocsc() A = sparse.linalg.splu(A) while True: if not all([t < d['T'], i < d['maxiter'], d['vec'](vec)]): if i <= miniter: # timestep too big log.info('Initial timestep too big, reducing to {}'.format( dt / 10)) return smoothen_vector(vec0, dt / 10, method=method, stop=stop) break vec = A.solve(vec) t += dt i += 1 else: raise "Unknown method '{}'".format(method) if d['vec'](vec): log.warning('Failed to reach the termination criterion') else: log.info('Criterion reached at t={} in {} iterations'.format(t, i)) return vec
def test_badarg(self): status, output = self._cli( '--bla') if self.method == 'run' else self._cli(funcname='bla') with self.subTest('argparse'): log.info(output) self.assertNotIn('all OK', output) with self.subTest('exitstatus'): self.assertIsNotNone(status) self.assertEqual(status.code, 2)
def constraint(self, c): g = self._g if self._absc is None: raise AssertionError('No constraints set.') log.info('Computing constraint ...') ret = constraint(self, *self._absc, c) log.info('Completed') return ret
def __new__(cls, g, order, f=None, **kwargs): ''' If the control mapping ``f`` is None return an instantiation of standard EGG. Else, return an instantiation of this class. ''' if f is None: log.info('No control mapping passed, proceeding with standard EGG') return Elliptic(g, order, **kwargs) return super(EllipticControl, cls).__new__(cls)
def backup(self): # Create logfiles and backups today = datetime.date.today() self.dir = '/home/niki/Documents/1_Master/0_Master_thesis/3_code/Auto/'+str(today) + '/' srcfile1 = '/home/niki/Documents/1_Master/0_Master_thesis/3_code/'+str(os.path.basename(__file__)) srcfile2 = '/home/niki/Documents/1_Master/0_Master_thesis/3_code/pre_post_lib.py' srcfile3 = '/home/niki/Documents/1_Master/0_Master_thesis/3_code/IGA_AM_lib.py' if not os.path.exists(self.dir): os.makedirs(self.dir) os.makedirs(self.dir + '2. Figures/') shutil.copy(srcfile1, self.dir) shutil.copy(srcfile2, self.dir) shutil.copy(srcfile3, self.dir) log.info('Backup made')
def __getitem__(self, key): """ Return blockshaped function evaluations (for test and trial spaces) """ try: ret = self._w[key] except KeyError: ret = self._w_eval(key) log.info(key + ' has been tabularized.') self._w[key] = ret except Exception as ex: raise Exception('Failed with unknown exception {}.'.format(ex)) finally: return ret
def test_badvalue(self): status, output = self._cli('--outrootdir=' + self.outrootdir, '--nopdb', '--iarg=1', '--farg=x', '--sarg=1') with self.subTest('outdir'): self.assertFalse( os.path.isdir(os.path.join(self.outrootdir, self.scriptname)), 'outdir directory found') with self.subTest('argparse'): log.info(output) self.assertNotIn('all OK', output) with self.subTest('exitstatus'): self.assertIsNotNone(status) self.assertEqual(status.code, 2)
def postprocess(domain, ns): # confirm that velocity is pointwise divergence-free div = domain.integrate('(u_k,k)^2' @ ns, geometry=ns.x, degree=9)**.5 log.info('velocity divergence: {:.2e}'.format(div)) # plot velocity field as streamlines, pressure field as contours x, u, p = domain.elem_eval([ns.x, ns.u, ns.p], ischeme='bezier9', separate=True) with plot.PyPlot('flow') as plt: tri = plt.mesh(x, mergetol=1e-5) plt.tricontour(tri, p, every=.01, linestyles='solid', alpha=.333) plt.colorbar() plt.streamplot(tri, u, spacing=.01, linewidth=-10, color='k', zorder=9)
def test_good(self): args = [ '--outrootdir=' + self.outrootdir, '--nopdb', '--iarg=1', '--farg=1', '--sarg=1' ] status, output = self._cli(*args) with self.subTest('outdir'): self.assertTrue( os.path.isdir(os.path.join(self.outrootdir, self.scriptname)), 'output directory not found') with self.subTest('argparse'): log.info(output) self.assertIn('all OK', output) with self.subTest('exitstatus'): self.assertIsNotNone(status) self.assertEqual(status.code, 0)
def __init__(self, g, order, absc=None): # any problems with ``g`` will be caught by the parent __init__ super().__init__(g, order) self._dindices = self._g.dofindices # The Jacobian-Determinant is evaluated in # the tensor-product points of xi and eta # as a constraint to warrant bijectivity of the result if isinstance(absc, int): # if an integer is passed to absc, we construct # abscissae that correspond to and ``absc``-order # Gauss quadrature scheme over all elements absc = fsol.make_quadrature(g, absc)[0] self._absc = absc if absc is not None: assert all( all( [aux.isincreasing(x_), x_[0] >= 0, x_[-1] <= 1] ) for x_ in absc ), \ 'Invalid constraint abscissae received.' _bsplev = lambda i, **kwargs: sparse.csr_matrix( self._splev(i, self._absc, **kwargs).ravel()[:, None]) structure = sparse.hstack([_bsplev(i) for i in range(self._N)]) self._w_xi = sparse.hstack( [_bsplev(i, dx=1) for i in range(self._N)]) self._w_eta = sparse.hstack( [_bsplev(i, dy=1) for i in range(self._N)]) # sparsity structure of the constraint jacobian self.jacobianstructure = \ sparse.hstack( [ structure, structure ] ).\ tolil()[:, self._dindices ].nonzero() log.info('Constraint jacobian sparsity pattern stored.') if not (self.constraint(self._g[self._dindices]) >= 0).all(): log.warning(''' Warning, the initial guess corresponding to the passed GridObject is not feasible. Unless another initial guess is specified, the optimizer will most likely fail. ''')
def constraint_gradient(self, c, sprs=False): if self._absc is None: raise AssertionError('No constraints set.') d = self._g.dofindices log.info('Computing constraint gradient ...') ret = constraint_jacobian(self, *self._absc, c, self._w_xi, self._w_eta)[:, d] log.info('Completed') if not sprs: return ret return sparse.csr_matrix(ret)
def gradient(self, c): log.info('Computing gradient') (x_xi, x_eta), (y_xi, y_eta) = self.all_fderivs(c) g11, g12, g22 = self.metric(c) mul00 = 2 * x_xi * g22 mul01 = 2 * x_eta * g11 mul10 = 2 * y_xi * g22 mul11 = 2 * y_eta * g11 arr = self.jitarray return \ np.concatenate( [ arr( mul=mul00, w='x' ) + arr( mul=mul01, w='y' ), arr( mul=mul10, w='x' ) + arr( mul=mul11, w='y' ) ] )
def printprop(self,extended = True, EXIT = False): t = PrettyTable(['Variable','Value','Explanation', 'Variable type']) sol = self.TOTAL[0] typecheck = sol[3] for item in range(0,len(self.TOTAL)): sol = self.TOTAL[item] if not typecheck == sol[3]: t.add_row([' ',' ',' ',' ']) t.add_row([sol[0], sol[1] ,sol[2], sol[3]]) typecheck = sol[3] log.user(t) # log.Log.write(3 , t ) if extended: t = PrettyTable(['What','Value','Explanation']) t.add_row(['Layerthickness', self.dx2/self.n ,'The thickness of the layer in [m]']) log.user(t) if EXIT: log.info('Exitted the script in printproperties' ) sys.exit()
def wrapper(): __log__ = log.clone() for item in __scope__.split('.'): __log__.append( item ) results0 = core.getprop('results') __results__ = [] t0 = time.time() try: f() except: exc, frames = debug.exc_info() log.stack( 'error: {}'.format(exc), frames ) results0.append(( __scope__, 3 )) if tbexplore: debug.explore( repr(exc), frames, '''Test package {!r} failed. The traceback explorer allows you to examine the failure state. Closing the explorer will resume testing with the next package.'''.format(__scope__) ) else: dt = time.time() - t0 npassed = sum( status == 0 for name, status in __results__ ) log.info( 'passed {}/{} tests in {:.2f} seconds'.format( npassed, len(__results__), dt ) ) results0.extend( __results__ )
def root(I, init=None, order=1, jac_options=None, **scipyargs): assert order in (1, 2) scipyargs.setdefault('verbose', True) scipyargs.setdefault('maxiter', 50) res = I.residual if init is None: init = I._g.x[I._g.dofindices] if jac_options is None: jac_options = {} if order == 1: jac = optimize.nonlin.KrylovJacobian(**jac_options) else: jac = SecondOrderKrylovJacobian(**jac_options) log.info('solving system with maxiter={}'.format(scipyargs['maxiter'])) return optimize.nonlin.nonlin_solve(res, init, jacobian=jac, **scipyargs)
def residual(self, c): J = self.jacdet(c) ret = (self._weights * J**2).sum() log.info(ret) return ret
def main( nelems: 'number of elements' = 20, epsilon: 'epsilon, 0 for automatic (based on nelems)' = 0, timestep: 'time step' = .01, maxtime: 'end time' = 1., theta: 'contact angle (degrees)' = 90, init: 'initial condition (random/bubbles)' = 'random', withplots: 'create plots' = True, ): mineps = 1./nelems if not epsilon: log.info('setting epsilon={}'.format(mineps)) epsilon = mineps elif epsilon < mineps: log.warning('epsilon under crititical threshold: {} < {}'.format(epsilon, mineps)) # create namespace ns = function.Namespace() ns.epsilon = epsilon ns.ewall = .5 * numpy.cos( theta * numpy.pi / 180 ) # construct mesh xnodes = ynodes = numpy.linspace(0,1,nelems+1) domain, ns.x = mesh.rectilinear( [ xnodes, ynodes ] ) # prepare bases ns.cbasis, ns.mubasis = function.chain([ domain.basis('spline', degree=2), domain.basis('spline', degree=2) ]) # polulate namespace ns.c = 'cbasis_n ?lhs_n' ns.c0 = 'cbasis_n ?lhs0_n' ns.mu = 'mubasis_n ?lhs_n' ns.f = '(6 c0 - 2 c0^3 - 4 c) / epsilon^2' # construct initial condition if init == 'random': numpy.random.seed(0) lhs0 = numpy.random.normal(0, .5, ns.cbasis.shape) elif init == 'bubbles': R1 = .25 R2 = numpy.sqrt(.5) * R1 # area2 = .5 * area1 ns.cbubble1 = function.tanh((R1-function.norm2(ns.x-(.5+R2/numpy.sqrt(2)+.8*ns.epsilon)))/ns.epsilon) ns.cbubble2 = function.tanh((R2-function.norm2(ns.x-(.5-R1/numpy.sqrt(2)-.8*ns.epsilon)))/ns.epsilon) sqr = domain.integral('(c - cbubble1 - cbubble2 - 1)^2 + mu^2' @ ns, geometry=ns.x, degree=4) lhs0 = solver.optimize('lhs', sqr) else: raise Exception( 'unknown init %r' % init ) # construct residual res = domain.integral('epsilon^2 cbasis_n,k mu_,k + mubasis_n (mu + f) - mubasis_n,k c_,k' @ ns, geometry=ns.x, degree=4) res -= domain.boundary.integral('mubasis_n ewall' @ ns, geometry=ns.x, degree=4) inertia = domain.integral('cbasis_n c' @ ns, geometry=ns.x, degree=4) # solve time dependent problem nsteps = numeric.round(maxtime/timestep) makeplots = MakePlots(domain, nsteps, ns) if withplots else lambda *args: None for istep, lhs in log.enumerate('timestep', solver.impliciteuler('lhs', target0='lhs0', residual=res, inertia=inertia, timestep=timestep, lhs0=lhs0)): makeplots(lhs) if istep == nsteps: break return lhs0, lhs
def runtests(): args = sys.argv[1:] # command line arguments if 'coverage' in sys.argv[0]: # coverage passes the complete commandline to `sys.argv` # find '-m tests' and keep the tail m = args.index('-m') assert args[m + 1] == __name__ args = args[m + 2:] __tbexplore__ = '--tbexplore' in args if __tbexplore__: args.remove('--tbexplore') if args: assert len(args) == 1 whitelist = args[0].split('.') else: whitelist = [] __richoutput__ = True __selfcheck__ = True __log__ = log._mklog() try: results = _runtests(PACKAGES, whitelist) except KeyboardInterrupt: log.info('aborted.') sys.exit(-1) except: exc, frames = debug.exc_info() log.stack('error in unit testing framework: {}'.format(exc), frames) log.info('crashed.') sys.exit(-2) summary = _summarize(results) ntests = sum(len(tests) for tests in summary.values()) passed = summary.pop(OK, []) failed = summary.pop(FAILED, []) error = summary.pop(ERROR, []) pkgerror = summary.pop(PKGERROR, []) log.info('{}/{} tests passed.'.format(len(passed), ntests)) if failed: log.info('* failures ({}):'.format(len(failed)), ', '.join(failed)) if error: log.info('* errors ({}):'.format(len(error)), ', '.join(error)) if pkgerror: log.info('* package failures ({}):'.format(len(pkgerror)), ', '.join(pkgerror)) if summary: log.info('* invalid status ({}) - this should not happen!'.format( len(summary))) sys.exit(ntests - len(passed))
def main( nelems: 'number of elements' = 12, viscosity: 'fluid viscosity' = 1e-3, density: 'fluid density' = 1, degree: 'polynomial degree' = 2, warp: 'warp domain (downward bend)' = False, tol: 'solver tolerance' = 1e-5, maxiter: 'maximum number if iterations, 0 for unlimited' = 0, withplots: 'create plots' = True, ): Re = density / viscosity # based on unit length and velocity log.user( 'reynolds number: {:.1f}'.format(Re) ) # construct mesh verts = numpy.linspace( 0, 1, nelems+1 ) domain, geom = mesh.rectilinear( [verts,verts] ) # construct bases vxbasis, vybasis, pbasis, lbasis = function.chain([ domain.basis( 'spline', degree=(degree+1,degree), removedofs=((0,-1),None) ), domain.basis( 'spline', degree=(degree,degree+1), removedofs=(None,(0,-1)) ), domain.basis( 'spline', degree=degree ), [1], # lagrange multiplier ]) if not warp: vbasis = function.stack( [ vxbasis, vybasis ], axis=1 ) else: gridgeom = geom xi, eta = gridgeom geom = (eta+2) * function.rotmat(xi*.4)[:,1] - (0,2) # slight downward bend J = geom.grad( gridgeom ) detJ = function.determinant( J ) vbasis = ( vxbasis[:,_] * J[:,0] + vybasis[:,_] * J[:,1] ) / detJ # piola transform pbasis /= detJ stressbasis = (2*viscosity) * vbasis.symgrad(geom) - (pbasis)[:,_,_] * function.eye( domain.ndims ) # construct matrices A = function.outer( vbasis.grad(geom), stressbasis ).sum([2,3]) \ + function.outer( pbasis, vbasis.div(geom)+lbasis ) \ + function.outer( lbasis, pbasis ) Ad = function.outer( vbasis.div(geom) ) stokesmat, divmat = domain.integrate( [ A, Ad ], geometry=geom, ischeme='gauss9' ) # define boundary conditions normal = geom.normal() utop = function.asarray([ normal[1], -normal[0] ]) h = domain.boundary.elem_eval( 1, geometry=geom, ischeme='gauss9', asfunction=True ) nietzsche = (2*viscosity) * ( ((degree+1)*2.5/h) * vbasis - vbasis.symgrad(geom).dotnorm(geom) ) stokesmat += domain.boundary.integrate( function.outer( nietzsche, vbasis ).sum(-1), geometry=geom, ischeme='gauss9' ) rhs = domain.boundary['top'].integrate( ( nietzsche * utop ).sum(-1), geometry=geom, ischeme='gauss9' ) # prepare plotting makeplots = MakePlots( domain, geom ) if withplots else lambda *args: None # start picard iterations lhs = stokesmat.solve( rhs, tol=tol, solver='cg', precon='spilu' ) for iiter in log.count( 'picard' ): log.info( 'velocity divergence:', divmat.matvec(lhs).dot(lhs) ) makeplots( vbasis.dot(lhs), pbasis.dot(lhs) ) ugradu = ( vbasis.grad(geom) * vbasis.dot(lhs) ).sum(-1) convection = density * function.outer( vbasis, ugradu ).sum(-1) matrix = stokesmat + domain.integrate( convection, ischeme='gauss9', geometry=geom ) lhs, info = matrix.solve( rhs, lhs0=lhs, tol=tol, info=True, precon='spilu', restart=999 ) if iiter == maxiter-1 or info.niter == 0: break return rhs, lhs
def _run(): __richoutput__ = True __selfcheck__ = True __log__ = log.clone() __results__ = [] try: for package in packages: package() except KeyboardInterrupt: log.info( 'aborted.' ) sys.exit( -1 ) except: exc, frames = debug.exc_info() log.stack( 'error in unit testing framework: {}'.format(exc), frames ) log.info( 'crashed.' ) sys.exit( -2 ) passed, failed, error, packagefail = results_by_status = [], [], [], [] for name, status in __results__: results_by_status[status].append( name ) log.info( '{}/{} tests passed.'.format( len(passed), len(__results__) ) ) if failed: log.info( '* failures ({}):'.format(len(failed)), ', '.join( failed ) ) if error: log.info( '* errors ({}):'.format(len(error)), ', '.join( error ) ) if packagefail: log.info( '* package failures ({}):'.format(len(packagefail)), ', '.join( packagefail ) ) sys.exit( len(__results__) - len(passed) )
def main( nelems: 'number of elements' = 12, viscosity: 'fluid viscosity' = 1e-2, density: 'fluid density' = 1, tol: 'solver tolerance' = 1e-12, rotation: 'cylinder rotation speed' = 0, timestep: 'time step' = 1/24, maxradius: 'approximate domain size' = 25, tmax: 'end time' = numpy.inf, degree: 'polynomial degree' = 2, withplots: 'create plots' = True, ): log.user('reynolds number: {:.1f}'.format(density / viscosity)) # based on unit length and velocity # create namespace ns = function.Namespace() ns.uinf = 1, 0 ns.density = density ns.viscosity = viscosity # construct mesh rscale = numpy.pi / nelems melems = numpy.ceil(numpy.log(2*maxradius) / rscale).astype(int) log.info('creating {}x{} mesh, outer radius {:.2f}'.format(melems, 2*nelems, .5*numpy.exp(rscale*melems))) domain, x0 = mesh.rectilinear([range(melems+1),numpy.linspace(0,2*numpy.pi,2*nelems+1)], periodic=(1,)) rho, phi = x0 phi += 1e-3 # tiny nudge (0.057 deg) to break element symmetry radius = .5 * function.exp(rscale * rho) ns.x = radius * function.trigtangent(phi) domain = domain.withboundary(inner='left', inflow=domain.boundary['right'].select(-ns.uinf.dotnorm(ns.x), ischeme='gauss1')) # prepare bases (using piola transformation to maintain u/p compatibility) J = ns.x.grad(x0) detJ = function.determinant(J) ns.unbasis, ns.utbasis, ns.pbasis = function.chain([ # compatible spaces using piola transformation domain.basis('spline', degree=(degree+1,degree), removedofs=((0,),None))[:,_] * J[:,0] / detJ, domain.basis('spline', degree=(degree,degree+1))[:,_] * J[:,1] / detJ, domain.basis('spline', degree=degree) / detJ, ]) ns.ubasis_ni = 'unbasis_ni + utbasis_ni' # populate namespace ns.u_i = 'ubasis_ni ?lhs_n' ns.p = 'pbasis_n ?lhs_n' ns.sigma_ij = 'viscosity (u_i,j + u_j,i) - p δ_ij' ns.hinner = 2 * numpy.pi / nelems ns.c = 5 * (degree+1) / ns.hinner ns.nietzsche_ni = 'viscosity (c ubasis_ni - (ubasis_ni,j + ubasis_nj,i) n_j)' ns.ucyl = -.5 * rotation * function.trignormal(phi) # create residual vector components res = domain.integral('ubasis_ni,j sigma_ij + pbasis_n u_k,k' @ ns, geometry=ns.x, degree=2*(degree+1)) res += domain.boundary['inner'].integral('nietzsche_ni (u_i - ucyl_i)' @ ns, geometry=ns.x, degree=2*(degree+1)) oseen = domain.integral('density ubasis_ni u_i,j uinf_j' @ ns, geometry=ns.x, degree=2*(degree+1)) convec = domain.integral('density ubasis_ni u_i,j u_j' @ ns, geometry=ns.x, degree=3*(degree+1)) inertia = domain.integral('density ubasis_ni u_i' @ ns, geometry=ns.x, degree=2*(degree+1)) # constrain full velocity vector at inflow sqr = domain.boundary['inflow'].integral('(u_i - uinf_i) (u_i - uinf_i)' @ ns, geometry=ns.x, degree=9) cons = solver.optimize('lhs', sqr, droptol=1e-15) # solve unsteady navier-stokes equations, starting from stationary oseen flow lhs0 = solver.solve_linear('lhs', res+oseen, constrain=cons) makeplots = MakePlots(domain, ns, timestep=timestep, rotation=rotation) if withplots else lambda *args: None for istep, lhs in log.enumerate('timestep', solver.impliciteuler('lhs', residual=res+convec, inertia=inertia, lhs0=lhs0, timestep=timestep, constrain=cons, newtontol=1e-10)): makeplots(lhs) if istep * timestep >= tmax: break return lhs0, lhs
def main( nelems: 'number of elements' = 20, epsilon: 'epsilon, 0 for automatic (based on nelems)' = 0, timestep: 'time step' = .01, maxtime: 'end time' = 1., theta: 'contact angle (degrees)' = 90, init: 'initial condition (random/bubbles)' = 'random', figures: 'create figures' = True, ): mineps = 1. / nelems if not epsilon: log.info('setting epsilon={}'.format(mineps)) epsilon = mineps elif epsilon < mineps: log.warning('epsilon under crititical threshold: {} < {}'.format( epsilon, mineps)) # create namespace ns = function.Namespace() ns.epsilon = epsilon ns.ewall = .5 * numpy.cos(theta * numpy.pi / 180) # construct mesh xnodes = ynodes = numpy.linspace(0, 1, nelems + 1) domain, ns.x = mesh.rectilinear([xnodes, ynodes]) # prepare bases ns.cbasis, ns.mubasis = function.chain( [domain.basis('spline', degree=2), domain.basis('spline', degree=2)]) # polulate namespace ns.c = 'cbasis_n ?lhs_n' ns.c0 = 'cbasis_n ?lhs0_n' ns.mu = 'mubasis_n ?lhs_n' ns.f = '(6 c0 - 2 c0^3 - 4 c) / epsilon^2' # construct initial condition if init == 'random': numpy.random.seed(0) lhs0 = numpy.random.normal(0, .5, ns.cbasis.shape) elif init == 'bubbles': R1 = .25 R2 = numpy.sqrt(.5) * R1 # area2 = .5 * area1 ns.cbubble1 = function.tanh( (R1 - function.norm2(ns.x - (.5 + R2 / numpy.sqrt(2) + .8 * ns.epsilon))) / ns.epsilon) ns.cbubble2 = function.tanh( (R2 - function.norm2(ns.x - (.5 - R1 / numpy.sqrt(2) - .8 * ns.epsilon))) / ns.epsilon) sqr = domain.integral('(c - cbubble1 - cbubble2 - 1)^2 + mu^2' @ ns, geometry=ns.x, degree=4) lhs0 = solver.optimize('lhs', sqr) else: raise Exception('unknown init %r' % init) # construct residual res = domain.integral( 'epsilon^2 cbasis_n,k mu_,k + mubasis_n (mu + f) - mubasis_n,k c_,k' @ ns, geometry=ns.x, degree=4) res -= domain.boundary.integral('mubasis_n ewall' @ ns, geometry=ns.x, degree=4) inertia = domain.integral('cbasis_n c' @ ns, geometry=ns.x, degree=4) # solve time dependent problem nsteps = numeric.round(maxtime / timestep) makeplots = MakePlots(domain, nsteps, ns) if figures else lambda *args: None for istep, lhs in log.enumerate( 'timestep', solver.impliciteuler('lhs', target0='lhs0', residual=res, inertia=inertia, timestep=timestep, lhs0=lhs0)): makeplots(lhs) if istep == nsteps: break return lhs0, lhs
def main( nelems: 'number of elements' = 20, epsilon: 'epsilon, 0 for automatic (based on nelems)' = 0, timestep: 'time step' = .01, maxtime: 'end time' = 1., theta: 'contact angle (degrees)' = 90, init: 'initial condition (random/bubbles)' = 'random', withplots: 'create plots' = True, ): mineps = 1. / nelems if not epsilon: log.info('setting epsilon=%f' % mineps) epsilon = mineps elif epsilon < mineps: log.warning('epsilon under crititical threshold: %f < %f' % (epsilon, mineps)) ewall = .5 * numpy.cos(theta * numpy.pi / 180) # construct mesh xnodes = ynodes = numpy.linspace(0, 1, nelems + 1) domain, geom = mesh.rectilinear([xnodes, ynodes]) # prepare bases cbasis, mubasis = function.chain( [domain.basis('spline', degree=2), domain.basis('spline', degree=2)]) # define mixing energy and splitting: F' = f_p - f_n F = lambda c_: (.5 / epsilon**2) * (c_**2 - 1)**2 f_p = lambda c_: (1. / epsilon**2) * 4 * c_ f_n = lambda c_: (1. / epsilon**2) * (6 * c_ - 2 * c_**3) # prepare matrix A = function.outer( cbasis ) \ + (timestep*epsilon**2) * function.outer( cbasis.grad(geom), mubasis.grad(geom) ).sum(-1) \ + function.outer( mubasis, mubasis - f_p(cbasis) ) \ - function.outer( mubasis.grad(geom), cbasis.grad(geom) ).sum(-1) matrix = domain.integrate(A, geometry=geom, ischeme='gauss4') # prepare wall energy right hand side rhs0 = domain.boundary.integrate(mubasis * ewall, geometry=geom, ischeme='gauss4') # construct initial condition if init == 'random': numpy.random.seed(0) c = cbasis.dot(numpy.random.normal(0, .5, cbasis.shape)) elif init == 'bubbles': R1 = .25 R2 = numpy.sqrt(.5) * R1 # area2 = .5 * area1 c = 1 + function.tanh( (R1-function.norm2(geom-(.5+R2/numpy.sqrt(2)+.8*epsilon)))/epsilon ) \ + function.tanh( (R2-function.norm2(geom-(.5-R1/numpy.sqrt(2)-.8*epsilon)))/epsilon ) else: raise Exception('unknown init %r' % init) # prepare plotting nsteps = numeric.round(maxtime / timestep) makeplots = MakePlots(domain, geom, nsteps, video=withplots == 'video') if withplots else lambda *args: None # start time stepping for istep in log.range('timestep', nsteps): Emix = F(c) Eiface = .5 * (c.grad(geom)**2).sum(-1) Ewall = (abs(ewall) + ewall * c) b = cbasis * c - mubasis * f_n(c) rhs, total, energy_mix, energy_iface = domain.integrate( [b, c, Emix, Eiface], geometry=geom, ischeme='gauss4') energy_wall = domain.boundary.integrate(Ewall, geometry=geom, ischeme='gauss4') log.user('concentration {}, energy {}'.format( total, energy_mix + energy_iface + energy_wall)) lhs = matrix.solve(rhs0 + rhs, tol=1e-12, restart=999) c = cbasis.dot(lhs) mu = mubasis.dot(lhs) makeplots(c, mu, energy_mix, energy_iface, energy_wall) return lhs, energy_mix, energy_iface, energy_wall
def _tablulate_control_mapping(self): ''' Tabulate the control mapping and all its required derivatives in the quadrature points. XXX: see if we can make this look prettier (possibly using some symbolic approach). ''' # by the time this is called, _f and _quad have been set # in the __init__ method _f = self._f _q = self._quad # all required first and second derivatives X_xi = _f(*_q, dx=1) X_xi_eta = _f(*_q, dx=1, dy=1) X_xi_xi = _f(*_q, dx=2) X_eta = _f(*_q, dy=1) X_eta_eta = _f(*_q, dy=2) _0 = (Ellipsis, 0) _1 = (Ellipsis, 1) # Jacobian determinant and its derivatives jacdet = X_xi[_0] * X_eta[_1] - X_eta[_0] * X_xi[_1] jacsqrt = jacdet**2 jacdet_xi = X_xi_xi[_0] * X_eta[_1] + X_xi[_0] * X_xi_eta[_1] \ - X_xi_eta[_0] * X_xi[_1] - X_eta[_0] * X_xi_xi[_1] jacdet_eta = X_xi_eta[_0] * X_eta[_1] + X_xi[_0] * X_eta_eta[_1] \ - X_eta_eta[_0] * X_xi[_1] - X_eta[_0] * X_xi_eta[_1] if not (jacdet > 0).all(): log.warning(''' Warning, the control mapping is defective on at least one quadrature point. Proceeding with this control mapping may lead to failure of convergence and / or a defective mapping. ''') # metric tensor of the control mapping divided by the Jacobian determinant self._G11 = (X_xi**2).sum(-1) / jacdet self._G12 = (X_xi * X_eta).sum(-1) / jacdet self._G22 = (X_eta**2).sum(-1) / jacdet # derivatives of _G11 self._G11_xi = \ 2 * ( X_xi * X_xi_xi ).sum(-1) / jacdet \ - jacdet_xi * (X_xi ** 2).sum(-1) / jacsqrt self._G11_eta = \ 2 * ( X_xi * X_xi_eta ).sum(-1) / jacdet \ - jacdet_eta * (X_xi ** 2).sum(-1) / jacsqrt # derivatives of _G12 self._G12_xi = \ (X_xi_xi * X_eta + X_xi * X_xi_eta).sum(-1) / jacdet \ - jacdet_xi * (X_xi * X_eta).sum(-1) / jacsqrt self._G12_eta = \ (X_xi_eta * X_eta + X_xi * X_eta_eta).sum(-1) / jacdet \ - jacdet_eta * (X_xi * X_eta).sum(-1) / jacsqrt # derivatives of _G22 self._G22_xi = \ 2 * ( X_eta * X_xi_eta ).sum(-1) / jacdet \ - jacdet_xi * (X_eta ** 2).sum(-1) / jacsqrt self._G22_eta = \ 2 * ( X_eta * X_eta_eta ).sum(-1) / jacdet \ - jacdet_eta * (X_eta ** 2).sum(-1) / jacsqrt log.info('The control mapping has been tabulated.')
def main( nelems: 'number of elements' = 12, viscosity: 'fluid viscosity' = 1e-2, density: 'fluid density' = 1, tol: 'solver tolerance' = 1e-12, rotation: 'cylinder rotation speed' = 0, timestep: 'time step' = 1/24, maxradius: 'approximate domain size' = 25, tmax: 'end time' = numpy.inf, degree: 'polynomial degree' = 2, figures: 'create figures' = True, ): log.user('reynolds number: {:.1f}'.format(density / viscosity)) # based on unit length and velocity # create namespace ns = function.Namespace() ns.uinf = 1, 0 ns.density = density ns.viscosity = viscosity # construct mesh rscale = numpy.pi / nelems melems = numpy.ceil(numpy.log(2*maxradius) / rscale).astype(int) log.info('creating {}x{} mesh, outer radius {:.2f}'.format(melems, 2*nelems, .5*numpy.exp(rscale*melems))) domain, x0 = mesh.rectilinear([range(melems+1),numpy.linspace(0,2*numpy.pi,2*nelems+1)], periodic=(1,)) rho, phi = x0 phi += 1e-3 # tiny nudge (0.057 deg) to break element symmetry radius = .5 * function.exp(rscale * rho) ns.x = radius * function.trigtangent(phi) domain = domain.withboundary(inner='left', inflow=domain.boundary['right'].select(-ns.uinf.dotnorm(ns.x), ischeme='gauss1')) # prepare bases (using piola transformation to maintain u/p compatibility) J = ns.x.grad(x0) detJ = function.determinant(J) ns.unbasis, ns.utbasis, ns.pbasis = function.chain([ # compatible spaces using piola transformation domain.basis('spline', degree=(degree+1,degree), removedofs=((0,),None))[:,_] * J[:,0] / detJ, domain.basis('spline', degree=(degree,degree+1))[:,_] * J[:,1] / detJ, domain.basis('spline', degree=degree) / detJ, ]) ns.ubasis_ni = 'unbasis_ni + utbasis_ni' # populate namespace ns.u_i = 'ubasis_ni ?lhs_n' ns.p = 'pbasis_n ?lhs_n' ns.sigma_ij = 'viscosity (u_i,j + u_j,i) - p δ_ij' ns.hinner = 2 * numpy.pi / nelems ns.c = 5 * (degree+1) / ns.hinner ns.nietzsche_ni = 'viscosity (c ubasis_ni - (ubasis_ni,j + ubasis_nj,i) n_j)' ns.ucyl = -.5 * rotation * function.trignormal(phi) # create residual vector components res = domain.integral('ubasis_ni,j sigma_ij + pbasis_n u_k,k' @ ns, geometry=ns.x, degree=2*(degree+1)) res += domain.boundary['inner'].integral('nietzsche_ni (u_i - ucyl_i)' @ ns, geometry=ns.x, degree=2*(degree+1)) oseen = domain.integral('density ubasis_ni u_i,j uinf_j' @ ns, geometry=ns.x, degree=2*(degree+1)) convec = domain.integral('density ubasis_ni u_i,j u_j' @ ns, geometry=ns.x, degree=3*(degree+1)) inertia = domain.integral('density ubasis_ni u_i' @ ns, geometry=ns.x, degree=2*(degree+1)) # constrain full velocity vector at inflow sqr = domain.boundary['inflow'].integral('(u_i - uinf_i) (u_i - uinf_i)' @ ns, geometry=ns.x, degree=9) cons = solver.optimize('lhs', sqr, droptol=1e-15) # solve unsteady navier-stokes equations, starting from stationary oseen flow lhs0 = solver.solve_linear('lhs', res+oseen, constrain=cons) makeplots = MakePlots(domain, ns, timestep=timestep, rotation=rotation) if figures else lambda *args: None for istep, lhs in log.enumerate('timestep', solver.impliciteuler('lhs', residual=res+convec, inertia=inertia, lhs0=lhs0, timestep=timestep, constrain=cons, newtontol=1e-10)): makeplots(lhs) if istep * timestep >= tmax: break return lhs0, lhs
def main( nelems: 'number of elements' = 12, viscosity: 'fluid viscosity' = 1e-2, density: 'fluid density' = 1, tol: 'solver tolerance' = 1e-12, rotation: 'cylinder rotation speed' = 0, timestep: 'time step' = 1/24, maxradius: 'approximate domain size' = 25, tmax: 'end time' = numpy.inf, withplots: 'create plots' = True, ): uinf = numpy.array([ 1, 0 ]) log.user( 'reynolds number:', density/viscosity ) # construct mesh rscale = numpy.pi / nelems melems = numpy.ceil( numpy.log(2*maxradius) / rscale ).astype( int ) log.info( 'creating {}x{} mesh, outer radius {:.2f}'.format( melems, 2*nelems, .5*numpy.exp(rscale*melems) ) ) domain, gridgeom = mesh.rectilinear( [range(melems+1),numpy.linspace(0,2*numpy.pi,2*nelems+1)], periodic=(1,) ) rho, phi = gridgeom phi += 1e-3 # tiny nudge (0.057 deg) to break element symmetry cylvelo = -.5 * rotation * function.trignormal(phi) radius = .5 * function.exp( rscale * rho ) geom = radius * function.trigtangent(phi) # prepare bases J = geom.grad( gridgeom ) detJ = function.determinant( J ) vnbasis, vtbasis, pbasis = function.chain([ # compatible spaces using piola transformation domain.basis( 'spline', degree=(3,2), removedofs=((0,),None) )[:,_] * J[:,0] / detJ, domain.basis( 'spline', degree=(2,3) )[:,_] * J[:,1] / detJ, domain.basis( 'spline', degree=2 ) / detJ, ]) vbasis = vnbasis + vtbasis stressbasis = (2*viscosity) * vbasis.symgrad(geom) - pbasis[:,_,_] * function.eye( domain.ndims ) # prepare matrices A = function.outer( vbasis.grad(geom), stressbasis ).sum([2,3]) + function.outer( pbasis, vbasis.div(geom) ) Ao = function.outer( vbasis, density * ( vbasis.grad(geom) * uinf ).sum(-1) ).sum(-1) At = (density/timestep) * function.outer( vbasis ).sum(-1) Ad = function.outer( vbasis.div(geom) ) stokesmat, uniconvec, inertmat, divmat = domain.integrate( [ A, Ao, At, Ad ], geometry=geom, ischeme='gauss9' ) # interior boundary condition (weak imposition of shear verlocity component) inner = domain.boundary['left'] h = inner.elem_eval( 1, geometry=geom, ischeme='gauss9', asfunction=True ) nietzsche = (2*viscosity) * ( (7.5/h) * vbasis - vbasis.symgrad(geom).dotnorm(geom) ) B = function.outer( nietzsche, vbasis ).sum(-1) b = ( nietzsche * cylvelo ).sum(-1) bcondmat, rhs = inner.integrate( [ B, b ], geometry=geom, ischeme='gauss9' ) stokesmat += bcondmat # exterior boundary condition (full velocity vector imposed at inflow) inflow = domain.boundary['right'].select( -( uinf * geom.normal() ).sum(-1), ischeme='gauss1' ) cons = inflow.project( uinf, onto=vbasis, geometry=geom, ischeme='gauss9', tol=1e-12 ) # initial condition (stationary oseen flow) lhs = (stokesmat+uniconvec).solve( rhs, constrain=cons, tol=0 ) # prepare plotting if not withplots: makeplots = lambda *args: None else: makeplots = MakePlots( domain, geom, video=withplots=='video', timestep=timestep ) mesh_ = domain.elem_eval( geom, ischeme='bezier5', separate=True ) inflow_ = inflow.elem_eval( geom, ischeme='bezier5', separate=True ) with plot.PyPlot( 'mesh', ndigits=0 ) as plt: plt.mesh( mesh_ ) plt.rectangle( makeplots.bbox[:,0], *( makeplots.bbox[:,1] - makeplots.bbox[:,0] ), ec='green' ) plt.segments( inflow_, colors='red' ) # start time stepping stokesmat += inertmat precon = (stokesmat+uniconvec).getprecon( 'splu', constrain=cons ) for istep in log.count( 'timestep', start=1 ): log.info( 'velocity divergence:', divmat.matvec(lhs).dot(lhs) ) convection = density * ( vbasis.grad(geom) * vbasis.dot(lhs) ).sum(-1) matrix = stokesmat + domain.integrate( function.outer( vbasis, convection ).sum(-1), ischeme='gauss9', geometry=geom ) lhs = matrix.solve( rhs + inertmat.matvec(lhs), lhs0=lhs, constrain=cons, tol=tol, restart=9999, precon=precon ) makeplots( vbasis.dot(lhs), pbasis.dot(lhs), istep*timestep*rotation ) if istep*timestep > tmax: break return lhs
def runtests(): args = sys.argv[1:] # command line arguments if 'coverage' in sys.argv[0]: # coverage passes the complete commandline to `sys.argv` # find '-m tests' and keep the tail m = args.index( '-m' ) assert args[m+1] == __name__ args = args[m+2:] __tbexplore__ = '--tbexplore' in args if __tbexplore__: args.remove( '--tbexplore' ) if args: assert len(args) == 1 whitelist = args[0].split( '.' ) else: whitelist = [] __richoutput__ = True __selfcheck__ = True __log__ = log._mklog() try: results = _runtests( PACKAGES, whitelist ) except KeyboardInterrupt: log.info( 'aborted.' ) sys.exit( -1 ) except: exc, frames = debug.exc_info() log.stack( 'error in unit testing framework: {}'.format(exc), frames ) log.info( 'crashed.' ) sys.exit( -2 ) summary = _summarize(results) ntests = sum( len(tests) for tests in summary.values() ) passed = summary.pop( OK, [] ) failed = summary.pop( FAILED, [] ) error = summary.pop( ERROR, [] ) pkgerror = summary.pop( PKGERROR, [] ) log.info( '{}/{} tests passed.'.format( len(passed), ntests ) ) if failed: log.info( '* failures ({}):'.format(len(failed)), ', '.join( failed ) ) if error: log.info( '* errors ({}):'.format(len(error)), ', '.join( error ) ) if pkgerror: log.info( '* package failures ({}):'.format(len(pkgerror)), ', '.join( pkgerror ) ) if summary: log.info( '* invalid status ({}) - this should not happen!'.format(len(summary)) ) sys.exit( ntests - len(passed) )
def main( uinf = 2.0, L = 2.0, R = 0.5, nelems = 7 , degree = 2 , maxrefine = 3 , withplots = True ): """`main` functions with different parameters. Parameters ---------- uinf : float free stream velocity L : float domain size R : float cylinder radius nelems : int number of elements degree : int b-spline degree maxrefine : int bisectioning steps withplots : bool create plots Returns ------- lhs : float solution φ err : float L2 norm, H1 norm and energy errors """ # construct mesh verts = numpy.linspace(-L/2, L/2, nelems+1) domain, geom = mesh.rectilinear([verts, verts]) # trim out a circle domain = domain.trim(function.norm2(geom)-R, maxrefine=maxrefine) # initialize namespace ns = function.Namespace() ns.R = R ns.x = geom ns.uinf = uinf # construct function space and lagrange multiplier ns.phibasis, ns.lbasis = function.chain([domain.basis('spline', degree=degree),[1.]]) ns.phi = ' phibasis_n ?lhs_n' ns.u = 'sqrt( (phibasis_n,i ?lhs_n) (phibasis_m,i ?lhs_m) )' ns.l = 'lbasis_n ?lhs_n' # set the exact solution ns.phiexact = 'uinf x_1 ( 1 - R^2 / (x_0^2 + x_1^2) )' # average is zero ns.phierror = 'phi - phiexact' # construct residual res = domain.integral('-phibasis_n,i phi_,i' @ ns, geometry=ns.x, degree=degree*2) res += domain.boundary.integral('phibasis_n phiexact_,i n_i' @ ns, geometry=ns.x, degree=degree*2) res += domain.integral('lbasis_n phi + l phibasis_n' @ ns, geometry=ns.x, degree=degree*2) # find lhs such that res == 0 and substitute this lhs in the namespace lhs = solver.solve_linear('lhs', res) ns = ns(lhs=lhs) # evaluate error err1 = numpy.sqrt(domain.integrate(['phierror phierror' @ns,'phierror phierror + phierror_,i phierror_,i' @ns, '0.5 phi_,i phi_,i' @ns], geometry=ns.x, degree=degree*4)) err2 = abs(err1[2] - 2.7710377946088443) err = numpy.array([err1[0],err1[1],err2]) log.info('errors: L2={:.2e}, H1={:.2e}, eh={:.2e}'.format(*err)) if withplots: makeplots(domain, ns) return lhs, err