Example #1
0
 def generate(self):
     treelog.user('my message')
     with treelog.infofile('test.dat', 'w') as f:
         f.write('test1')
     with treelog.context('my context'):
         with treelog.iter.plain('iter', 'abc') as items:
             for c in items:
                 treelog.info(c)
         with treelog.context('empty'):
             pass
         treelog.error('multiple..\n  ..lines')
         with treelog.userfile('test.dat', 'wb') as f:
             treelog.info('generating')
             f.write(b'test2')
     self.generate_test()
     with treelog.context('context step={}', 0) as format:
         treelog.info('foo')
         format(1)
         treelog.info('bar')
     with treelog.errorfile('same.dat', 'wb') as f:
         f.write(b'test3')
     with treelog.debugfile('dbg.dat', 'wb') as f:
         f.write(b'test4')
     treelog.debug('dbg')
     treelog.warning('warn')
Example #2
0
 def test_surface(self):
   trimsurface = self.pos.boundary['trimmed'].volume(self.geom)
   trimerr = abs(trimsurface - self.exact_trimsurface) / self.exact_trimsurface
   log.user('trim surface error:', trimerr)
   totalsurface = self.pos.boundary.volume(self.geom)
   totalerr = abs(totalsurface - self.exact_totalsurface) / self.exact_totalsurface
   log.user('total surface error:', totalerr)
   self.assertLess(trimerr, self.errtol, 'trim surface tolerance not met')
   self.assertLess(totalerr, self.errtol, 'total surface tolerance not met')
Example #3
0
 def __exit__(self, type_, value, backtrace):
     super().__exit__(type_, value, backtrace)
     if value is not None:
         self.pvd.close()
     else:
         self.pvd.write('  </Collection>\n')
         self.pvd.write('</VTKFile>\n')
         self.pvd.close()
         log.user(self.rootfile)
Example #4
0
    def step(self, stepdata: StepData):
        with super().step(stepdata) as step:
            yield step

        filename = self.make_filename(with_step=True)
        writer = self.get_writer()
        writer.SetFileName(str(filename))
        writer.SetInputData(self.grid)
        writer.Write()

        log.user(filename)
Example #5
0
File: vtf.py Project: TheBB/SISO
    def __exit__(self, *args, **kwargs):
        for fname, data in self.field_blocks.items():
            with data.blocktype() as fblock:
                fblock.SetName(fname)
                for stepid, rblocks in data.steps.items():
                    fblock.BindResultBlocks(stepid, *rblocks)

        self.gblock.__exit__(*args, **kwargs)
        self.exit_stateinfo()
        self.out.__exit__(*args, **kwargs)
        super().__exit__(*args, **kwargs)
        log.user(self.make_filename())
Example #6
0
    def run_single(self, num, index, namespace):
        log.user(', '.join(f'{k}={repr(v)}' for k, v in namespace.items()))
        self.evaluate_context(namespace)
        namespace['_index'] = num

        collector = ResultCollector(self._types)
        for key, value in namespace.items():
            collector.collect(key, value)

        namespace.update(self._constants)

        with TemporaryDirectory() as workpath:
            workpath = Path(workpath)

            if self._logdir:
                logdir = self.storagepath / render(self._logdir, namespace)
                logdir.mkdir(parents=True, exist_ok=True)
            else:
                logdir = None

            log.debug(
                f"Using SRC='{self.sourcepath}', WRK='{workpath}', LOG='{logdir}'"
            )

            for filemap in self._pre_files:
                filemap.copy(namespace,
                             self.sourcepath,
                             workpath,
                             sourcename='SRC',
                             targetname='WRK')

            success = True
            for command in self._commands:
                if not command.run(collector, namespace, workpath, logdir):
                    self.commit_result(index, collector)
                    success = False
                    break

            if logdir:
                for filemap in self._post_files:
                    filemap.copy(namespace,
                                 workpath,
                                 logdir,
                                 sourcename='WRK',
                                 targetname='LOG',
                                 ignore_missing=not success)

        self.commit_result(index, collector)
        return success
Example #7
0
    def update_geometry(self, geometry: Field, patch: Patch, data: Array2D):
        if not isinstance(patch.topology, StructuredTopology):
            raise TypeError("SIMRA writer does not support unstructured grids")
        nodeshape = tuple(s + 1 for s in patch.topology.shape)
        data = data.reshape(*nodeshape, 3)
        data = fix_orientation(data)
        cellshape = tuple(s - 1 for s in data.shape[:-1])
        cells = structured_cells(cellshape, 3) + 1
        cells[:, 1], cells[:, 3] = cells[:, 3].copy(), cells[:, 1].copy()
        cells[:, 5], cells[:, 7] = cells[:, 7].copy(), cells[:, 5].copy()

        # Compute macro elements
        rshape = tuple(c - 1 for c in cellshape)
        mcells = structured_cells(tuple(c - 1 for c in cellshape), 3).reshape(
            *rshape, -1) + 1
        mcells = mcells[::2, ::2, ::2, ...].transpose((1, 0, 2, 3))
        mcells = mcells.reshape(-1, 8)
        mcells[:, 1], mcells[:, 3] = mcells[:, 3].copy(), mcells[:, 1].copy()
        mcells[:, 5], mcells[:, 7] = mcells[:, 7].copy(), mcells[:, 5].copy()

        # Write single precision
        f4_dtype, u4_dtype = dtypes(config.output_endianness)
        data = data.astype(f4_dtype)
        cells = cells.astype(u4_dtype)
        mcells = mcells.astype(u4_dtype)

        with FortranFile(self.outpath, 'w', header_dtype=u4_dtype) as f:
            f.write_record(
                np.array([
                    data.size // 3,
                    cells.size // 8,
                    data.shape[1],
                    data.shape[0],
                    data.shape[2],
                    mcells.size // 8,
                ],
                         dtype=u4_dtype))
            f.write_record(data.flatten())
            f.write_record(cells.flatten())
            f.write_record(mcells.flatten())
        log.user(self.outpath)
Example #8
0
def main(nelems: int, etype: str, btype: str, degree: int, traction: float,
         maxrefine: int, radius: float, poisson: float):
    '''
  Horizontally loaded linear elastic plate with FCM hole.

  .. arguments::

     nelems [9]
       Number of elements along edge.
     etype [square]
       Type of elements (square/triangle/mixed).
     btype [std]
       Type of basis function (std/spline), with availability depending on the
       selected element type.
     degree [2]
       Polynomial degree.
     traction [.1]
       Far field traction (relative to Young's modulus).
     maxrefine [2]
       Number or refinement levels used for the finite cell method.
     radius [.5]
       Cut-out radius.
     poisson [.3]
       Poisson's ratio, nonnegative and strictly smaller than 1/2.
  '''

    domain0, geom = mesh.unitsquare(nelems, etype)
    domain = domain0.trim(function.norm2(geom) - radius, maxrefine=maxrefine)

    ns = function.Namespace()
    ns.x = geom
    ns.lmbda = 2 * poisson
    ns.mu = 1 - poisson
    ns.ubasis = domain.basis(btype, degree=degree).vector(2)
    ns.u_i = 'ubasis_ni ?lhs_n'
    ns.X_i = 'x_i + u_i'
    ns.strain_ij = '(d(u_i, x_j) + d(u_j, x_i)) / 2'
    ns.stress_ij = 'lmbda strain_kk δ_ij + 2 mu strain_ij'
    ns.r2 = 'x_k x_k'
    ns.R2 = radius**2 / ns.r2
    ns.k = (3 - poisson) / (1 + poisson)  # plane stress parameter
    ns.scale = traction * (1 + poisson) / 2
    ns.uexact_i = 'scale (x_i ((k + 1) (0.5 + R2) + (1 - R2) R2 (x_0^2 - 3 x_1^2) / r2) - 2 δ_i1 x_1 (1 + (k - 1 + R2) R2))'
    ns.du_i = 'u_i - uexact_i'

    sqr = domain.boundary['left,bottom'].integral('(u_i n_i)^2 J(x)' @ ns,
                                                  degree=degree * 2)
    cons = solver.optimize('lhs', sqr, droptol=1e-15)
    sqr = domain.boundary['top,right'].integral('du_k du_k J(x)' @ ns,
                                                degree=20)
    cons = solver.optimize('lhs', sqr, droptol=1e-15, constrain=cons)

    res = domain.integral('d(ubasis_ni, x_j) stress_ij J(x)' @ ns,
                          degree=degree * 2)
    lhs = solver.solve_linear('lhs', res, constrain=cons)

    bezier = domain.sample('bezier', 5)
    X, stressxx = bezier.eval(['X', 'stress_00'] @ ns, lhs=lhs)
    export.triplot('stressxx.png',
                   X,
                   stressxx,
                   tri=bezier.tri,
                   hull=bezier.hull)

    err = domain.integral('<du_k du_k, sum:ij(d(du_i, x_j)^2)>_n J(x)' @ ns,
                          degree=max(degree, 3) * 2).eval(lhs=lhs)**.5
    treelog.user('errors: L2={:.2e}, H1={:.2e}'.format(*err))

    return err, cons, lhs
Example #9
0
def main(nelems: int, etype: str, btype: str, degree: int):
    '''
  Laplace problem on a unit square.

  .. arguments::

     nelems [10]
       Number of elements along edge.
     etype [square]
       Type of elements (square/triangle/mixed).
     btype [std]
       Type of basis function (std/spline), availability depending on the
       selected element type.
     degree [1]
       Polynomial degree.
  '''

    # A unit square domain is created by calling the
    # :func:`nutils.mesh.unitsquare` mesh generator, with the number of elements
    # along an edge as the first argument, and the type of elements ("square",
    # "triangle", or "mixed") as the second. The result is a topology object
    # ``domain`` and a vectored valued geometry function ``geom``.

    domain, geom = mesh.unitsquare(nelems, etype)

    # To be able to write index based tensor contractions, we need to bundle all
    # relevant functions together in a namespace. Here we add the geometry ``x``,
    # a scalar ``basis``, and the solution ``u``. The latter is formed by
    # contracting the basis with a to-be-determined solution vector ``?lhs``.

    ns = function.Namespace()
    ns.x = geom
    ns.basis = domain.basis(btype, degree=degree)
    ns.u = 'basis_n ?lhs_n'

    # We are now ready to implement the Laplace equation. In weak form, the
    # solution is a scalar field :math:`u` for which:
    #
    # .. math:: ∀ v: ∫_Ω \frac{dv}{dx_i} \frac{du}{dx_i} - ∫_{Γ_n} v f = 0.
    #
    # By linearity the test function :math:`v` can be replaced by the basis that
    # spans its space. The result is an integral ``res`` that evaluates to a
    # vector matching the size of the function space.

    res = domain.integral('d(basis_n, x_i) d(u, x_i) J(x)' @ ns,
                          degree=degree * 2)
    res -= domain.boundary['right'].integral(
        'basis_n cos(1) cosh(x_1) J(x)' @ ns, degree=degree * 2)

    # The Dirichlet constraints are set by finding the coefficients that minimize
    # the error:
    #
    # .. math:: \min_u ∫_{\Gamma_d} (u - u_d)^2
    #
    # The resulting ``cons`` array holds numerical values for all the entries of
    # ``?lhs`` that contribute (up to ``droptol``) to the minimization problem.
    # All remaining entries are set to ``NaN``, signifying that these degrees of
    # freedom are unconstrained.

    sqr = domain.boundary['left'].integral('u^2 J(x)' @ ns, degree=degree * 2)
    sqr += domain.boundary['top'].integral(
        '(u - cosh(1) sin(x_0))^2 J(x)' @ ns, degree=degree * 2)
    cons = solver.optimize('lhs', sqr, droptol=1e-15)

    # The unconstrained entries of ``?lhs`` are to be determined such that the
    # residual vector evaluates to zero in the corresponding entries. This step
    # involves a linearization of ``res``, resulting in a jacobian matrix and
    # right hand side vector that are subsequently assembled and solved. The
    # resulting ``lhs`` array matches ``cons`` in the constrained entries.

    lhs = solver.solve_linear('lhs', res, constrain=cons)

    # Once all entries of ``?lhs`` are establised, the corresponding solution can
    # be vizualised by sampling values of ``ns.u`` along with physical
    # coordinates ``ns.x``, with the solution vector provided via the
    # ``arguments`` dictionary. The sample members ``tri`` and ``hull`` provide
    # additional inter-point information required for drawing the mesh and
    # element outlines.

    bezier = domain.sample('bezier', 9)
    x, u = bezier.eval(['x', 'u'] @ ns, lhs=lhs)
    export.triplot('solution.png', x, u, tri=bezier.tri, hull=bezier.hull)

    # To confirm that our computation is correct, we use our knowledge of the
    # analytical solution to evaluate the L2-error of the discrete result.

    err = domain.integral('(u - sin(x_0) cosh(x_1))^2 J(x)' @ ns,
                          degree=degree * 2).eval(lhs=lhs)**.5
    treelog.user('L2 error: {:.2e}'.format(err))

    return cons, lhs, err
Example #10
0
def main(etype: str, btype: str, degree: int, nrefine: int):
    '''
  Adaptively refined Laplace problem on an L-shaped domain.

  .. arguments::

     etype [square]
       Type of elements (square/triangle/mixed).
     btype [h-std]
       Type of basis function (h/th-std/spline), with availability depending on
       the configured element type.
     degree [2]
       Polynomial degree
     nrefine [5]
       Number of refinement steps to perform.
  '''

    domain, geom = mesh.unitsquare(2, etype)

    x, y = geom - .5
    exact = (x**2 + y**2)**(1 / 3) * function.cos(
        function.arctan2(y + x, y - x) * (2 / 3))
    domain = domain.trim(exact - 1e-15, maxrefine=0)
    linreg = util.linear_regressor()

    with treelog.iter.fraction('level', range(nrefine + 1)) as lrange:
        for irefine in lrange:

            if irefine:
                refdom = domain.refined
                ns.refbasis = refdom.basis(btype, degree=degree)
                indicator = refdom.integral(
                    'd(refbasis_n, x_k) d(u, x_k) J(x)' @ ns,
                    degree=degree * 2).eval(lhs=lhs)
                indicator -= refdom.boundary.integral(
                    'refbasis_n d(u, x_k) n(x_k) J(x)' @ ns,
                    degree=degree * 2).eval(lhs=lhs)
                supp = ns.refbasis.get_support(
                    indicator**2 > numpy.mean(indicator**2))
                domain = domain.refined_by(refdom.transforms[supp])

            ns = function.Namespace()
            ns.x = geom
            ns.basis = domain.basis(btype, degree=degree)
            ns.u = 'basis_n ?lhs_n'
            ns.du = ns.u - exact

            sqr = domain.boundary['trimmed'].integral('u^2 J(x)' @ ns,
                                                      degree=degree * 2)
            cons = solver.optimize('lhs', sqr, droptol=1e-15)

            sqr = domain.boundary.integral('du^2 J(x)' @ ns, degree=7)
            cons = solver.optimize('lhs', sqr, droptol=1e-15, constrain=cons)

            res = domain.integral('d(basis_n, x_k) d(u, x_k) J(x)' @ ns,
                                  degree=degree * 2)
            lhs = solver.solve_linear('lhs', res, constrain=cons)

            ndofs = len(ns.basis)
            error = domain.integral('<du^2, sum:k(d(du, x_k)^2)>_i J(x)' @ ns,
                                    degree=7).eval(lhs=lhs)**.5
            rate, offset = linreg.add(numpy.log(len(ns.basis)),
                                      numpy.log(error))
            treelog.user(
                'ndofs: {ndofs}, L2 error: {error[0]:.2e} ({rate[0]:.2f}), H1 error: {error[1]:.2e} ({rate[1]:.2f})'
                .format(ndofs=len(ns.basis), error=error, rate=rate))

            bezier = domain.sample('bezier', 9)
            x, u, du = bezier.eval(['x', 'u', 'du'] @ ns, lhs=lhs)
            export.triplot('sol.png', x, u, tri=bezier.tri, hull=bezier.hull)
            export.triplot('err.png', x, du, tri=bezier.tri, hull=bezier.hull)

    return ndofs, error, lhs
def main(nrefine: int, traction: float, radius: float, poisson: float):
    '''
  Horizontally loaded linear elastic plate with IGA hole.

  .. arguments::

     nrefine [2]
       Number of uniform refinements starting from 1x2 base mesh.
     traction [.1]
       Far field traction (relative to Young's modulus).
     radius [.5]
       Cut-out radius.
     poisson [.3]
       Poisson's ratio, nonnegative and strictly smaller than 1/2.
  '''

    # create the coarsest level parameter domain
    domain, geom0 = mesh.rectilinear([1, 2])
    bsplinebasis = domain.basis('spline', degree=2)
    controlweights = numpy.ones(12)
    controlweights[1:3] = .5 + .25 * numpy.sqrt(2)
    weightfunc = bsplinebasis.dot(controlweights)
    nurbsbasis = bsplinebasis * controlweights / weightfunc

    # create geometry function
    indices = [0, 2], [1, 2], [2, 1], [2, 0]
    controlpoints = numpy.concatenate([
        numpy.take([0, 2**.5 - 1, 1], indices) * radius,
        numpy.take([0, .3, 1], indices) * (radius + 1) / 2,
        numpy.take([0, 1, 1], indices)
    ])
    geom = (nurbsbasis[:, numpy.newaxis] * controlpoints).sum(0)

    radiuserr = domain.boundary['left'].integral(
        (function.norm2(geom) - radius)**2 * function.J(geom0),
        degree=9).eval()**.5
    treelog.info('hole radius exact up to L2 error {:.2e}'.format(radiuserr))

    # refine domain
    if nrefine:
        domain = domain.refine(nrefine)
        bsplinebasis = domain.basis('spline', degree=2)
        controlweights = domain.project(weightfunc,
                                        onto=bsplinebasis,
                                        geometry=geom0,
                                        ischeme='gauss9')
        nurbsbasis = bsplinebasis * controlweights / weightfunc

    ns = function.Namespace()
    ns.x = geom
    ns.lmbda = 2 * poisson
    ns.mu = 1 - poisson
    ns.ubasis = nurbsbasis.vector(2)
    ns.u_i = 'ubasis_ni ?lhs_n'
    ns.X_i = 'x_i + u_i'
    ns.strain_ij = '(d(u_i, x_j) + d(u_j, x_i)) / 2'
    ns.stress_ij = 'lmbda strain_kk δ_ij + 2 mu strain_ij'
    ns.r2 = 'x_k x_k'
    ns.R2 = radius**2 / ns.r2
    ns.k = (3 - poisson) / (1 + poisson)  # plane stress parameter
    ns.scale = traction * (1 + poisson) / 2
    ns.uexact_i = 'scale (x_i ((k + 1) (0.5 + R2) + (1 - R2) R2 (x_0^2 - 3 x_1^2) / r2) - 2 δ_i1 x_1 (1 + (k - 1 + R2) R2))'
    ns.du_i = 'u_i - uexact_i'

    sqr = domain.boundary['top,bottom'].integral('(u_i n_i)^2 J(x)' @ ns,
                                                 degree=9)
    cons = solver.optimize('lhs', sqr, droptol=1e-15)
    sqr = domain.boundary['right'].integral('du_k du_k J(x)' @ ns, degree=20)
    cons = solver.optimize('lhs', sqr, droptol=1e-15, constrain=cons)

    # construct residual
    res = domain.integral('d(ubasis_ni, x_j) stress_ij J(x)' @ ns, degree=9)

    # solve system
    lhs = solver.solve_linear('lhs', res, constrain=cons)

    # vizualize result
    bezier = domain.sample('bezier', 9)
    X, stressxx = bezier.eval(['X', 'stress_00'] @ ns, lhs=lhs)
    export.triplot('stressxx.png',
                   X,
                   stressxx,
                   tri=bezier.tri,
                   hull=bezier.hull,
                   clim=(numpy.nanmin(stressxx), numpy.nanmax(stressxx)))

    # evaluate error
    err = domain.integral('<du_k du_k, sum:ij(d(du_i, x_j)^2)>_n J(x)' @ ns,
                          degree=9).eval(lhs=lhs)**.5
    treelog.user('errors: L2={:.2e}, H1={:.2e}'.format(*err))

    return err, cons, lhs
Example #12
0
 def test_volume(self):
   volume = self.pos.volume(self.geom)
   volerr = abs(volume - self.exact_volume) / self.exact_volume
   log.user('volume error:', volerr)
   self.assertLess(volerr, self.errtol, 'volume tolerance not met')
Example #13
0
def main(nelems: int, etype: str, btype: str, degree: int,
         epsilon: typing.Optional[float], contactangle: float, timestep: float,
         mtol: float, seed: int, circle: bool, stab: stab):
    '''
  Cahn-Hilliard equation on a unit square/circle.

  .. arguments::

     nelems [20]
       Number of elements along domain edge.
     etype [square]
       Type of elements (square/triangle/mixed).
     btype [std]
       Type of basis function (std/spline), with availability depending on the
       configured element type.
     degree [2]
       Polynomial degree.
     epsilon []
       Interface thickness; defaults to an automatic value based on the
       configured mesh density if left unspecified.
     contactangle [90]
       Wall contact angle in degrees.
     timestep [.01]
       Time step.
     mtol [.01]
       Threshold value for chemical potential peak to peak difference, used as
       a stop criterion.
     seed [0]
       Random seed for the initial condition.
     circle [no]
       Select circular domain as opposed to a unit square.
     stab [linear]
       Stabilization method (linear/optimal/none).
  '''

    mineps = 1. / nelems
    if epsilon is None:
        treelog.info('setting epsilon={}'.format(mineps))
        epsilon = mineps
    elif epsilon < mineps:
        treelog.warning('epsilon under crititical threshold: {} < {}'.format(
            epsilon, mineps))

    domain, geom = mesh.unitsquare(nelems, etype)
    bezier = domain.sample('bezier', 5)  # sample for plotting

    ns = function.Namespace()
    if not circle:
        ns.x = geom
    else:
        angle = (geom - .5) * (numpy.pi / 2)
        ns.x = function.sin(angle) * function.cos(angle)[[1, 0
                                                          ]] / numpy.sqrt(2)
    ns.epsilon = epsilon
    ns.ewall = .5 * numpy.cos(contactangle * numpy.pi / 180)
    ns.cbasis = ns.mbasis = domain.basis('std', degree=degree)
    ns.c = 'cbasis_n ?c_n'
    ns.dc = 'cbasis_n (?c_n - ?c0_n)'
    ns.m = 'mbasis_n ?m_n'
    ns.F = '.5 (c^2 - 1)^2 / epsilon^2'
    ns.dF = stab.value
    ns.dt = timestep

    nrg_mix = domain.integral('F J(x)' @ ns, degree=7)
    nrg_iface = domain.integral('.5 sum:k(d(c, x_k)^2) J(x)' @ ns, degree=7)
    nrg_wall = domain.boundary.integral('(abs(ewall) + c ewall) J(x)' @ ns,
                                        degree=7)
    nrg = nrg_mix + nrg_iface + nrg_wall + domain.integral(
        '(dF - m dc - .5 dt epsilon^2 sum:k(d(m, x_k)^2)) J(x)' @ ns, degree=7)

    numpy.random.seed(seed)
    state = dict(c=numpy.random.normal(0, .5, ns.cbasis.shape),
                 m=numpy.random.normal(0, .5,
                                       ns.mbasis.shape))  # initial condition

    with treelog.iter.plain('timestep', itertools.count()) as steps:
        for istep in steps:

            E = sample.eval_integrals(nrg_mix, nrg_iface, nrg_wall, **state)
            treelog.user(
                'energy: {0:.3f} ({1[0]:.0f}% mixture, {1[1]:.0f}% interface, {1[2]:.0f}% wall)'
                .format(sum(E), 100 * numpy.array(E) / sum(E)))

            x, c, m = bezier.eval(['x', 'c', 'm'] @ ns, **state)
            export.triplot('phase.png', x, c, tri=bezier.tri, clim=(-1, 1))
            export.triplot('chempot.png', x, m, tri=bezier.tri)

            if numpy.ptp(m) < mtol:
                break

            state['c0'] = state['c']
            state = solver.optimize(['c', 'm'],
                                    nrg,
                                    arguments=state,
                                    tol=1e-10)

    return state
Example #14
0
 def __exit__(self, *args):
     self.out.__exit__(*args)
     log.user(self.outpath)
     return super().__exit__(*args)
Example #15
0
  return iter(title, builtins.range(*args))

def enumerate(title, iterable):
  warnings.deprecation('log.enumerate is deprecated; use log.iter.percentage instead')
  return iter(title, builtins.enumerate(iterable), length=_len(iterable))

def zip(title, *iterables):
  warnings.deprecation('log.zip is deprecated; use log.iter.percentage instead')
  return iter(title, builtins.zip(*iterables), length=min(map(_len, iterables)))

def count(title, start=0, step=1):
  warnings.deprecation('log.count is deprecated; use log.iter.percentage instead')
  return iter(title, itertools.count(start, step))

if distutils.version.StrictVersion(treelog.version) >= distutils.version.StrictVersion('1.0b5'):
  from treelog import debug, info, user, warning, error, debugfile, infofile, userfile, warningfile, errorfile, context
else:
  debug = lambda *args, **kwargs: treelog.debug(*args, **kwargs)
  info = lambda *args, **kwargs: treelog.info(*args, **kwargs)
  user = lambda *args, **kwargs: treelog.user(*args, **kwargs)
  warning = lambda *args, **kwargs: treelog.warning(*args, **kwargs)
  error = lambda *args, **kwargs: treelog.error(*args, **kwargs)
  debugfile = lambda *args, **kwargs: treelog.debugfile(*args, **kwargs)
  infofile = lambda *args, **kwargs: treelog.infofile(*args, **kwargs)
  userfile = lambda *args, **kwargs: treelog.userfile(*args, **kwargs)
  warningfile = lambda *args, **kwargs: treelog.warningfile(*args, **kwargs)
  errorfile = lambda *args, **kwargs: treelog.errorfile(*args, **kwargs)
  context = lambda *args, **kwargs: treelog.context(title, *initargs, **initkwargs)

# vim:sw=2:sts=2:et