← Back to team overview

dolfin team mailing list archive

Re: [jobh@xxxxxxxxx: Fwd: Logging]

 

Applied (with only minor changes).

I had to change DEBUG to DGG since the build system sets the flag
-DDEBUG when compiling.

Would it be better to change that flag to -DDOLFIN_DEBUG?

--
Anders


On Fri, Mar 26, 2010 at 12:43:20PM +0100, Anders Logg wrote:
> Attached is a patch from Joachim containing some improvements to the
> log system. I think it looks good, and it matches the Python logging
> system quite well (which we use from UFL and FFC).
>
> I'll comment more on it later and apply the patch.
>

Return-Path: <jobh@xxxxxxxxx>
Received: from mail-imap5.uio.no ([unix socket])
	by mail-imap5.uio.no (Cyrus v2.2.12) with LMTPA;
	Fri, 26 Mar 2010 10:21:37 +0100
X-Sieve: CMU Sieve 2.2
Delivery-date: Fri, 26 Mar 2010 10:21:37 +0100
Received: from mail-mx5.uio.no ([129.240.10.46])
	by mail-imap5.uio.no with esmtp (Exim 4.69)
	(envelope-from <jobh@xxxxxxxxx>) id 1Nv5jV-0005tt-4M
	for logg@xxxxxxxxx; Fri, 26 Mar 2010 10:21:37 +0100
Received: from [128.39.37.254] (helo=[192.168.100.115])
	by mail-mx5.uio.no with esmtpsa (TLSv1:CAMELLIA256-SHA:256)
	user jobh (Exim 4.69) (envelope-from <jobh@xxxxxxxxx>)
	id 1Nv5jT-00013O-Jq
	for logg@xxxxxxxxx; Fri, 26 Mar 2010 10:21:37 +0100
Message-ID: <4BAC7C9D.8080105@xxxxxxxxx>
Date: Fri, 26 Mar 2010 10:21:33 +0100
From: Joachim Berdal Haga <jobh@xxxxxxxxx>
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US;
	rv:1.9.1.8) Gecko/20100316 Thunderbird/3.0.3
To: logg@xxxxxxxxx
Subject: Fwd: Logging
X-UiO-Ratelimit-Test: rcpts/h 1 msgs/h 1 sum rcpts/h 1 sum msgs/h 1 total
	rcpts 457 max rcpts/h 10 ratelimit 0
X-UiO-MailScanner: No virus found
X-UiO-Spam-info: not spam, SpamAssassin (score=-5.0, required=5.0,
	autolearn=disabled, UIO_MAIL_IS_INTERNAL=-5, uiobl=NO,
	uiouri=NO)
X-UiO-Scanned: 2B07FA87B73D199C7DB6E283A51430B1183B8E84
X-UiO-SPAM-Test: remote_host: 128.39.37.254 spam_score: -49 maxlevel 30
	minaction 1 bait 0 mail/h: 7 total 27938 max/h 66 blacklist 0
	greylist 0 ratelimit 0
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="------------050006000707090307060000"
Content-Disposition: inline
>
> Hei, jeg sendte denne til dolfin-lista på onsdag, men det ser ikke
> ut som om den kom gjennom. Er lista lukket? Har ikke fått noen
> bounce.
>
> -j.
>
>
> -------- Original Message --------
> Subject: Logging
> Date: Wed, 24 Mar 2010 16:46:48 +0100
> From: Joachim Berdal Haga <jobh@xxxxxxxxx>
> To: dolfin@xxxxxxxxxxxxxxxxxxx
>
> I've recently had the pleasure to use dolfin again (through ascot), and
> it occurred to me that dolfin is very verbose, to the point where my own
> output is lost in the haystack. While the logging framework includes a
> log_level argument to info(), it is not much used, perhaps because the
> meaning of the log levels is not defined or documented. The result is
> that logging is in practice either on or off.
>
> The following bundle rectifies this situation, by (a) defining log
> levels, (b) using them. The default logging level is now less verbose,
> and it can be modified in a meaningful way by set_log_level() and not
> only be logging(false).
>
> I copied the log levels from the python logging module, and added a
> couple in between. As a result, the log level changes meaning from
> (lower == more severe) to (higher == more severe). The levels are (from
> LogLevel.h):
>
>      CRITICAL  = 50,             /* errors that may lead to data
> corruption and suchlike */
>      ERROR     = 40,             /* things that go boom */
>      WARNING   = 30,             /* things that may go boom later */
>      INFO      = 20,             /* information of general interest */
>      PROGRESS  = 16,             /* what's happening (broadly) */
>      TRACE     = 13,             /* what's happening (in detail) */
>      DEBUG     = 10              /* sundry */
>
> Note some deficiencies in this patch: (1) the levels are not exported to
> python; (2) the levels for the various info() calls were chosen very
> quickly and "by ear", and, (3) I don't know the original design/plan for
> how the logging was supposed to be used, and this may be the wrong way
> to do it (i.e., should a call to info(TRACE, msg) instead be a call to
> trace(msg)? Should a "standard" logging framework be used? Should info()
> be called log() and have a mandatory severity argument, so that the user
> is forced to think about it?)
>
> A change to the progress output is also included which prints the
> progress bar in-line with the title. This cuts down the number of lines
> a lot. Vertical space is precious in this wide-screen age.
>
> I'm not subscribed to the list btw.
>
> -j.
>

> # Bazaar merge directive format 2 (Bazaar 0.90)
> # revision_id: jobh@rodin-20100324145048-uwyapvgdytgrirkb
> # target_branch: http://bazaar.launchpad.net/~dolfin-core/dolfin/main/
> # testament_sha1: 33c3dbaa065dd48a46e72f7b32fa1941aa3932e1
> # timestamp: 2010-03-24 15:51:43 +0100
> # base_revision_id: logg@xxxxxxxxx-20100126125337-y1ikvifyi5c1jikj
> #
> # Begin patch
> === modified file 'dolfin/common/timing.cpp'
> --- dolfin/common/timing.cpp	2009-08-10 20:06:04 +0000
> +++ dolfin/common/timing.cpp	2010-03-24 14:50:48 +0000
> @@ -26,6 +26,8 @@
>    clock_t __toc_time = std::clock();
>
>    double elapsed_time = ((double) (__toc_time - __tic_time)) / CLOCKS_PER_SEC;
> +  if (elapsed_time < 1e-10)
> +    elapsed_time = 0;
>
>    return elapsed_time;
>  }
>
> === modified file 'dolfin/fem/DirichletBC.cpp'
> --- dolfin/fem/DirichletBC.cpp	2009-12-03 08:48:41 +0000
> +++ dolfin/fem/DirichletBC.cpp	2010-03-24 10:33:06 +0000
> @@ -343,7 +343,7 @@
>        values[i] = x_values[i] - values[i];
>    }
>
> -  info("Applying boundary conditions to linear system.");
> +  info(PROGRESS, "Applying boundary conditions to linear system.");
>
>    // Modify RHS vector (b[i] = value) and apply changes
>    if (b)
> @@ -576,7 +576,7 @@
>    const DofMap& dofmap = _function_space->dofmap();
>
>    // Initialize facets, needed for geometric search
> -  info("Computing facets, needed for geometric application of boundary conditions.");
> +  info(TRACE, "Computing facets, needed for geometric application of boundary conditions.");
>    mesh.init(mesh.topology().dim() - 1);
>
>    // Iterate over facets
>
> === modified file 'dolfin/fem/DofMap.cpp'
> --- dolfin/fem/DofMap.cpp	2009-11-17 13:09:50 +0000
> +++ dolfin/fem/DofMap.cpp	2010-03-23 15:50:40 +0000
> @@ -130,8 +130,8 @@
>    // Recursively extract UFC sub dofmap
>    boost::shared_ptr<ufc::dof_map>
>      ufc_sub_dof_map(extract_sub_dofmap(*_ufc_dofmap, ufc_offset, component, _ufc_mesh, dolfin_mesh));
> -  info(2, "Extracted dof map for sub system: %s", ufc_sub_dof_map->signature());
> -  info(2, "Offset for sub system: %d", ufc_offset);
> +  info(DEBUG, "Extracted dof map for sub system: %s", ufc_sub_dof_map->signature());
> +  info(DEBUG, "Offset for sub system: %d", ufc_offset);
>
>    // Create dofmap
>    DofMap* sub_dofmap = 0;
>
> === modified file 'dolfin/fem/DofMapBuilder.cpp'
> --- dolfin/fem/DofMapBuilder.cpp	2009-11-04 10:46:13 +0000
> +++ dolfin/fem/DofMapBuilder.cpp	2010-03-24 10:33:06 +0000
> @@ -47,7 +47,7 @@
>  {
>    // FIXME: Split this function into two; deciding ownership and then renumbering
>
> -  info("Building parallel dof map");
> +  info(TRACE, "Building parallel dof map");
>
>    // Check that dof map has not been built
>    if (dofmap._map.get())
> @@ -223,6 +223,6 @@
>
>    delete [] _dofmap;
>
> -  info("Finished building parallel dof map");
> +  info(TRACE, "Finished building parallel dof map");
>  }
>  //-----------------------------------------------------------------------------
>
> === modified file 'dolfin/fem/EqualityBC.cpp'
> --- dolfin/fem/EqualityBC.cpp	2009-11-06 10:10:55 +0000
> +++ dolfin/fem/EqualityBC.cpp	2010-03-24 10:33:06 +0000
> @@ -76,7 +76,7 @@
>  //-----------------------------------------------------------------------------
>  void EqualityBC::apply(GenericMatrix& A, GenericVector& b) const
>  {
> -  info("Applying equality boundary conditions to linear system.");
> +  info(TRACE, "Applying equality boundary conditions to linear system.");
>
>    if (equal_dofs.size() < 2)
>    {
>
> === modified file 'dolfin/fem/FiniteElement.cpp'
> --- dolfin/fem/FiniteElement.cpp	2009-11-04 10:46:13 +0000
> +++ dolfin/fem/FiniteElement.cpp	2010-03-23 15:50:40 +0000
> @@ -21,7 +21,7 @@
>  {
>    // Recursively extract sub element
>    boost::shared_ptr<const FiniteElement> sub_finite_element = extract_sub_element(*this, component);
> -  info(2, "Extracted finite element for sub system: %s", sub_finite_element->signature().c_str());
> +  info(DEBUG, "Extracted finite element for sub system: %s", sub_finite_element->signature().c_str());
>
>    return sub_finite_element;
>  }
>
> === modified file 'dolfin/fem/Form.cpp'
> --- dolfin/fem/Form.cpp	2010-01-26 12:53:37 +0000
> +++ dolfin/fem/Form.cpp	2010-03-24 10:33:06 +0000
> @@ -211,8 +211,8 @@
>      assert(element.get());
>      if (element->signature() != _function_spaces[i]->element().signature())
>      {
> -      info("Expected element: %s", element->signature());
> -      info("Input element:    %s", _function_spaces[i]->element().signature().c_str());
> +      info(ERROR, "Expected element: %s", element->signature());
> +      info(ERROR, "Input element:    %s", _function_spaces[i]->element().signature().c_str());
>        error("Wrong type of function space for argument %d.", i);
>      }
>    }
>
> === modified file 'dolfin/fem/SystemAssembler.cpp'
> --- dolfin/fem/SystemAssembler.cpp	2009-10-08 19:11:44 +0000
> +++ dolfin/fem/SystemAssembler.cpp	2010-03-24 10:33:06 +0000
> @@ -76,7 +76,7 @@
>                                            bool add_values)
>  {
>    Timer timer("Assemble system");
> -  info("Assembling linear system and applying boundary conditions...");
> +  info(PROGRESS, "Assembling linear system and applying boundary conditions...");
>
>    // FIXME: 1. Need consistency check between a and L
>    // FIXME: 2. Some things can be simplified since we know it's a matrix and a vector
>
> === modified file 'dolfin/io/MFile.cpp'
> --- dolfin/io/MFile.cpp	2009-05-18 17:17:47 +0000
> +++ dolfin/io/MFile.cpp	2010-03-23 15:50:40 +0000
> @@ -58,7 +58,7 @@
>    // Close file
>    fclose(fp);
>
> -  info("Saved vector to file %s in Octave/MATLAB format.", filename.c_str());
> +  info(TRACE, "Saved vector to file %s in Octave/MATLAB format.", filename.c_str());
>  }
>  //-----------------------------------------------------------------------------
>  void MFile::operator<<(const Mesh& mesh)
> @@ -150,7 +150,7 @@
>    // Increase the number of meshes saved to this file
>    counter++;
>
> -  info(1, "Saved mesh %s (%s) to file %s in Octave/MATLAB format.",
> +  info(TRACE, "Saved mesh %s (%s) to file %s in Octave/MATLAB format.",
>            mesh.name().c_str(), mesh.label().c_str(), filename.c_str());
>  }
>  //-----------------------------------------------------------------------------
>
> === modified file 'dolfin/io/MatlabFile.cpp'
> --- dolfin/io/MatlabFile.cpp	2009-05-02 20:55:48 +0000
> +++ dolfin/io/MatlabFile.cpp	2010-03-23 15:50:40 +0000
> @@ -60,9 +60,9 @@
>    // Close file
>    fclose(fp);
>
> -//  info(1, "Saved matrix %s (%s) to file %s in sparse MATLAB format",
> +//  info(TRACE, "Saved matrix %s (%s) to file %s in sparse MATLAB format",
>  //          A.name().c_str(), A.label().c_str(), filename.c_str());
> -  info(1, "Saved matrix to file %s in sparse MATLAB format", filename.c_str());
> +  info(TRACE, "Saved matrix to file %s in sparse MATLAB format", filename.c_str());
>  }
>  //-----------------------------------------------------------------------------
>
>
> === modified file 'dolfin/io/OctaveFile.cpp'
> --- dolfin/io/OctaveFile.cpp	2009-05-02 20:55:48 +0000
> +++ dolfin/io/OctaveFile.cpp	2010-03-23 15:50:40 +0000
> @@ -60,9 +60,9 @@
>    fclose(fp);
>    delete [] row;
>
> -//  info(1, "Saved matrix %s (%s) to file %s in Octave format.",
> +//  info(TRACE, "Saved matrix %s (%s) to file %s in Octave format.",
>  //          A.name().c_str(), A.label().c_str(), filename.c_str());
>
> -  info(1, "Saved matrix to file %s in Octave format.", filename.c_str());
> +  info(TRACE, "Saved matrix to file %s in Octave format.", filename.c_str());
>  }
>  //-----------------------------------------------------------------------------
>
> === modified file 'dolfin/io/VTKFile.cpp'
> --- dolfin/io/VTKFile.cpp	2009-12-01 23:34:47 +0000
> +++ dolfin/io/VTKFile.cpp	2010-03-23 15:50:40 +0000
> @@ -71,7 +71,7 @@
>    // Finalise and write pvd files
>    finalize(vtu_filename);
>
> -  info(1, "Saved mesh %s (%s) to file %s in VTK format.",
> +  info(TRACE, "Saved mesh %s (%s) to file %s in VTK format.",
>            mesh.name().c_str(), mesh.label().c_str(), filename.c_str());
>  }
>  //----------------------------------------------------------------------------
> @@ -123,7 +123,7 @@
>    // Finalise and write pvd files
>    finalize(vtu_filename);
>
> -  info(1, "Saved function %s (%s) to file %s in VTK format.",
> +  info(TRACE, "Saved function %s (%s) to file %s in VTK format.",
>            u.name().c_str(), u.label().c_str(), filename.c_str());
>  }
>  //----------------------------------------------------------------------------
>
> === modified file 'dolfin/io/XMLFile.cpp'
> --- dolfin/io/XMLFile.cpp	2010-01-04 20:03:57 +0000
> +++ dolfin/io/XMLFile.cpp	2010-03-23 15:50:40 +0000
> @@ -94,7 +94,7 @@
>                                       stderr);
>    ret = xmlRelaxNGValidateDoc(validator, document);
>    if ( ret == 0 ) {
> -    info(0, "%s validates", filename.c_str());
> +    info(DEBUG, "%s validates", filename.c_str());
>    }
>    else if ( ret < 0 ) {
>      error("%s failed to load", filename.c_str());
>
> === modified file 'dolfin/io/XMLFile.h'
> --- dolfin/io/XMLFile.h	2010-01-04 20:03:57 +0000
> +++ dolfin/io/XMLFile.h	2010-03-23 15:50:40 +0000
> @@ -134,7 +134,7 @@
>
>      template<class T> void read_xml_map(T& map)
>      {
> -      info(1, "Reading map from file %s.", filename.c_str());
> +      info(TRACE, "Reading map from file %s.", filename.c_str());
>        XMLMap xml_map(map, *this);
>        XMLDolfin xml_dolfin(xml_map, *this);
>        xml_dolfin.handle();
> @@ -145,7 +145,7 @@
>
>      template<class T> void read_xml_array(T& x)
>      {
> -      info(1, "Reading array from file %s.", filename.c_str());
> +      info(TRACE, "Reading array from file %s.", filename.c_str());
>        XMLArray xml_array(x, *this);
>        XMLDolfin xml_dolfin(xml_array, *this);
>        xml_dolfin.handle();
>
> === modified file 'dolfin/la/CholmodCholeskySolver.cpp'
> --- dolfin/la/CholmodCholeskySolver.cpp	2009-12-10 11:38:15 +0000
> +++ dolfin/la/CholmodCholeskySolver.cpp	2010-03-24 10:33:06 +0000
> @@ -67,7 +67,7 @@
>  	             (double*) std::tr1::get<2>(data), M, nnz);
>
>    // Factorize
> -  info("Cholesky-factorizing linear system of size %d x %d (CHOLMOD).",M,M);
> +  info(PROGRESS, "Cholesky-factorizing linear system of size %d x %d (CHOLMOD).",M,M);
>    cholmod.factorize();
>
>    return 1;
> @@ -86,7 +86,7 @@
>    // Initialise solution vector and solve
>    x.resize(N);
>
> -  info("Solving factorized linear system of size %d x %d (CHOLMOD).", N, N);
> +  info(PROGRESS, "Solving factorized linear system of size %d x %d (CHOLMOD).", N, N);
>
>    cholmod.factorized_solve(x.data(), b.data());
>
> @@ -156,7 +156,7 @@
>  					  uint M, uint nz)
>  {
>    if(factorized)
> -    info(1, "CholeskySolver already contains a factorized matrix! Clearing and starting over.");
> +    info(DEBUG, "CholeskySolver already contains a factorized matrix! Clearing and starting over.");
>
>    // Clear any data
>    clear();
>
> === modified file 'dolfin/la/DefaultFactory.cpp'
> --- dolfin/la/DefaultFactory.cpp	2009-09-21 18:15:02 +0000
> +++ dolfin/la/DefaultFactory.cpp	2010-03-24 10:33:06 +0000
> @@ -79,7 +79,7 @@
>    }
>
>    // Fallback
> -  info("Linear algebra backend \"" + backend + "\" not available, using " + default_backend + ".");
> +  info(WARNING, "Linear algebra backend \"" + backend + "\" not available, using " + default_backend + ".");
>    return DefaultFactory::instance();
>  }
>  //-----------------------------------------------------------------------------
>
> === modified file 'dolfin/la/EpetraKrylovSolver.cpp'
> --- dolfin/la/EpetraKrylovSolver.cpp	2009-09-08 16:38:36 +0000
> +++ dolfin/la/EpetraKrylovSolver.cpp	2010-03-24 10:33:06 +0000
> @@ -108,7 +108,7 @@
>
>    // Write a message
>    if (parameters["report"])
> -    info("Solving linear system of size %d x %d (Krylov solver).", M, N);
> +    info(PROGRESS, "Solving linear system of size %d x %d (Krylov solver).", M, N);
>
>    // Reinitialize solution vector if necessary
>    if (x.size() != M)
> @@ -199,7 +199,7 @@
>    // Start solve
>    linear_solver.Iterate(parameters["maximum_iterations"], parameters["relative_tolerance"]);
>
> -  info("AztecOO Krylov solver (%s, %s) converged in %d iterations.",
> +  info(PROGRESS, "AztecOO Krylov solver (%s, %s) converged in %d iterations.",
>            method.c_str(), pc_type.c_str(), linear_solver.NumIters());
>
>    return linear_solver.NumIters();
>
> === modified file 'dolfin/la/ITLKrylovSolver.cpp'
> --- dolfin/la/ITLKrylovSolver.cpp	2009-09-08 16:38:36 +0000
> +++ dolfin/la/ITLKrylovSolver.cpp	2010-03-24 10:33:06 +0000
> @@ -107,7 +107,7 @@
>
>    // Check exit condition
>    if(errno_ == 0)
> -    info("ITLSolver (%s, %s) converged in %d iterations. Resid=%8.2e",
> +    info(PROGRESS, "ITLSolver (%s, %s) converged in %d iterations. Resid=%8.2e",
>  	    method.c_str(), pc_type.c_str(), iter.iterations(), iter.resid());
>    else
>      warning("ITLKrylovSolver: (%s, %s) failed to converge!\n\t%d iterations,"
>
> === modified file 'dolfin/la/KrylovSolver.cpp'
> --- dolfin/la/KrylovSolver.cpp	2009-10-28 17:00:27 +0000
> +++ dolfin/la/KrylovSolver.cpp	2010-03-23 15:50:40 +0000
> @@ -41,7 +41,7 @@
>    p.add("maximum_iterations",  10000);
>    p.add("gmres_restart",       30);
>    p.add("shift_nonzero",       0.0);
> -  p.add("report",              true);
> +  p.add("report",              true); /* deprecate? */
>    p.add("monitor_convergence", false);
>
>    return p;
>
> === modified file 'dolfin/la/LAPACKSolvers.cpp'
> --- dolfin/la/LAPACKSolvers.cpp	2009-12-15 13:22:38 +0000
> +++ dolfin/la/LAPACKSolvers.cpp	2010-03-24 10:33:06 +0000
> @@ -31,7 +31,7 @@
>    double* work = new double[m*lwork];
>
>    // Call DGELSS
> -  info("Solving least squares system of size %d x %d using DGELS.", m, n);
> +  info(PROGRESS, "Solving least squares system of size %d x %d using DGELS.", m, n);
>    dgels(&trans, &m, &n, &nrhs, A.values, &lda, b.values, &ldb, work, &lwork, &status);
>
>    // Check output status
>
> === modified file 'dolfin/la/PETScKrylovSolver.cpp'
> --- dolfin/la/PETScKrylovSolver.cpp	2009-09-27 19:11:40 +0000
> +++ dolfin/la/PETScKrylovSolver.cpp	2010-03-24 10:33:06 +0000
> @@ -112,8 +112,7 @@
>      error("Non-matching dimensions for linear system.");
>
>    // Write a message
> -  if (parameters["report"])
> -    info("Solving linear system of size %d x %d (Krylov solver).", M, N);
> +  info(PROGRESS, "Solving linear system of size %d x %d (Krylov solver).", M, N);
>
>    // Reinitialize KSP solver if necessary
>    init(M, N);
> @@ -173,8 +172,7 @@
>      error("Non-matching dimensions for linear system.");
>
>    // Write a message
> -  if (parameters["report"])
> -    info("Solving virtual linear system of size %d x %d (Krylov solver).", M, N);
> +  info(PROGRESS, "Solving virtual linear system of size %d x %d (Krylov solver).", M, N);
>
>    // Reinitialize KSP solver if necessary
>    init(M, N);
> @@ -255,7 +253,7 @@
>    // Set up solver environment
>    if (MPI::num_processes() > 1)
>    {
> -    info("Creating parallel PETSc Krylov solver.");
> +    info(TRACE, "Creating parallel PETSc Krylov solver.");
>      KSPCreate(PETSC_COMM_WORLD, ksp.get());
>    }
>    else
> @@ -374,10 +372,6 @@
>  //-----------------------------------------------------------------------------
>  void PETScKrylovSolver::write_report(int num_iterations)
>  {
> -  // Check if we should write the report
> -  if (!parameters["report"])
> -    return;
> -
>    // Get name of solver and preconditioner
>    const KSPType ksp_type;
>    const PCType pc_type;
> @@ -388,7 +382,7 @@
>    PCGetType(pc, &pc_type);
>
>    // Report number of iterations and solver type
> -  info("PETSc Krylov solver (%s, %s) converged in %d iterations.",
> +  info(PROGRESS, "PETSc Krylov solver (%s, %s) converged in %d iterations.",
>            ksp_type, pc_type, num_iterations);
>  }
>  //-----------------------------------------------------------------------------
>
> === modified file 'dolfin/la/PETScLUSolver.cpp'
> --- dolfin/la/PETScLUSolver.cpp	2009-09-28 12:21:23 +0000
> +++ dolfin/la/PETScLUSolver.cpp	2010-03-24 10:33:06 +0000
> @@ -68,7 +68,7 @@
>
>    // Write a message
>    if (report)
> -    info("Solving linear system of size %d x %d (PETSc LU solver, %s).",
> +    info(PROGRESS, "Solving linear system of size %d x %d (PETSc LU solver, %s).",
>           A.size(0), A.size(1), solver_type);
>
>    // Solve linear system
> @@ -98,7 +98,7 @@
>
>    // Write a message
>    if ( report )
> -    info("Solving linear system of size %d x %d (PETSc LU solver).",
> +    info(PROGRESS, "Solving linear system of size %d x %d (PETSc LU solver).",
>  		A.size(0), A.size(1));
>
>    // Solve linear system
> @@ -155,7 +155,7 @@
>    // Set up solver environment
>    if (MPI::num_processes() > 1)
>    {
> -    info("Creating parallel PETSc Krylov solver (for LU factorization).");
> +    info(TRACE, "Creating parallel PETSc Krylov solver (for LU factorization).");
>      KSPCreate(PETSC_COMM_WORLD, &ksp);
>    }
>    else
>
> === modified file 'dolfin/la/SLEPcEigenSolver.cpp'
> --- dolfin/la/SLEPcEigenSolver.cpp	2009-12-02 19:49:45 +0000
> +++ dolfin/la/SLEPcEigenSolver.cpp	2010-03-23 15:50:40 +0000
> @@ -166,7 +166,7 @@
>
>    const EPSType eps_type = 0;
>    EPSGetType(eps, &eps_type);
> -  info("Eigenvalue solver (%s) converged in %d iterations.",
> +  info(PROGRESS, "Eigenvalue solver (%s) converged in %d iterations.",
>         eps_type, num_iterations);
>  }
>  //-----------------------------------------------------------------------------
>
> === modified file 'dolfin/la/SingularSolver.cpp'
> --- dolfin/la/SingularSolver.cpp	2009-09-08 16:38:36 +0000
> +++ dolfin/la/SingularSolver.cpp	2010-03-24 10:33:06 +0000
> @@ -31,7 +31,7 @@
>                                     GenericVector& x,
>                                     const GenericVector& b)
>  {
> -  info("Solving singular system...");
> +  info(TRACE, "Solving singular system...");
>
>    // Propagate parameters
>    linear_solver.parameters.update(parameters("linear_solver"));
> @@ -60,7 +60,7 @@
>                                     const GenericVector& b,
>                                     const GenericMatrix& M)
>  {
> -  info("Solving singular system...");
> +  info(TRACE, "Solving singular system...");
>
>    // Propagate parameters
>    linear_solver.parameters.update(parameters("linear_solver"));
> @@ -171,7 +171,7 @@
>    assert(B);
>    assert(c);
>
> -  info("Creating extended hopefully non-singular system...");
> +  info(TRACE, "Creating extended hopefully non-singular system...");
>
>    // Reset matrix
>    B->zero();
>
> === modified file 'dolfin/la/SparsityPattern.cpp'
> --- dolfin/la/SparsityPattern.cpp	2010-01-02 15:34:51 +0000
> +++ dolfin/la/SparsityPattern.cpp	2010-03-23 15:50:40 +0000
> @@ -194,7 +194,8 @@
>      return;
>
>    // Print some useful information
> -  info_statistics();
> +  if (get_log_level() <= DEBUG)
> +    info_statistics();
>
>    // Communicate non-local blocks if any
>    if (row_range_min != 0 || row_range_max != shape[0])
>
> === modified file 'dolfin/la/UmfpackLUSolver.cpp'
> --- dolfin/la/UmfpackLUSolver.cpp	2009-12-10 11:38:15 +0000
> +++ dolfin/la/UmfpackLUSolver.cpp	2010-03-24 10:33:06 +0000
> @@ -73,7 +73,7 @@
>      (const long int*) std::tr1::get<1>(data), std::tr1::get<2>(data), M, nnz);
>
>    // Factorize
> -  info("LU-factorizing linear system of size %d x %d (UMFPACK).", M, M);
> +  info(PROGRESS, "LU-factorizing linear system of size %d x %d (UMFPACK).", M, M);
>    umfpack.factorize();
>
>    return 1;
> @@ -92,7 +92,7 @@
>    // Initialise solution vector and solve
>    x.resize(N);
>
> -  info("Solving factorized linear system of size %d x %d (UMFPACK).", N, N);
> +  info(PROGRESS, "Solving factorized linear system of size %d x %d (UMFPACK).", N, N);
>    // Solve for tranpose since we use compressed rows and UMFPACK expected compressed columns
>    umfpack.factorized_solve(x.data(), b.data(), true);
>
>
> === added file 'dolfin/log/LogLevel.h'
> --- dolfin/log/LogLevel.h	1970-01-01 00:00:00 +0000
> +++ dolfin/log/LogLevel.h	2010-03-23 15:50:40 +0000
> @@ -0,0 +1,19 @@
> +#ifndef __LOGLEVEL_H
> +#define __LOGLEVEL_H
> +
> +namespace dolfin
> +{
> +  /* These match the levels in the python 'logging' module (and adds trace/progress) */
> +
> +  enum LogLevel {
> +    CRITICAL  = 50,             /* errors that may lead to data corruption and suchlike */
> +    ERROR     = 40,             /* things that go boom */
> +    WARNING   = 30,             /* things that may go boom later */
> +    INFO      = 20,             /* information of general interest */
> +    PROGRESS  = 16,             /* what's happening (broadly) */
> +    TRACE     = 13,             /* what's happening (in detail) */
> +    DEBUG     = 10              /* sundry */
> +  };
> +}
> +
> +#endif
>
> === modified file 'dolfin/log/Logger.cpp'
> --- dolfin/log/Logger.cpp	2009-09-15 11:57:07 +0000
> +++ dolfin/log/Logger.cpp	2010-03-23 15:50:40 +0000
> @@ -25,7 +25,7 @@
>
>  //-----------------------------------------------------------------------------
>  Logger::Logger()
> -  : active(true), log_level(0), indentation_level(0), logstream(&std::cout),
> +  : active(true), log_level(PROGRESS), indentation_level(0), logstream(&std::cout),
>      process_number(-1)
>  {
>    if (MPI::num_processes() > 1)
> @@ -61,7 +61,7 @@
>  void Logger::warning(std::string msg) const
>  {
>    std::string s = std::string("*** Warning: ") + msg;
> -  write(0, s);
> +  write(WARNING, s);
>  }
>  //-----------------------------------------------------------------------------
>  void Logger::error(std::string msg) const
> @@ -84,34 +84,24 @@
>  //-----------------------------------------------------------------------------
>  void Logger::progress(std::string title, double p) const
>  {
> -  int N = DOLFIN_TERM_WIDTH - 15;
> -  int n = static_cast<int>(p*static_cast<double>(N));
> -
> -  // Print the title
> -  std::string s = "| " + title;
> -  for (uint i = 0; i < (N - title.size() - 1); i++)
> -    s += " ";
> -  s += "|";
> -  write(0, s);
> -
> -  // Print the progress bar
> -  s = "|";
> +  std::stringstream line;
> +  line << title << " [";
> +
> +  const int N = DOLFIN_TERM_WIDTH - title.size() - 12 - 2*indentation_level;
> +  const int n = static_cast<int>(p*static_cast<double>(N));
> +
>    for (int i = 0; i < n; i++)
> -    s += "=";
> -  if (n > 0 && n < N)
> -  {
> -    s += "|";
> -    n++;
> -  }
> -  for (int i = n; i < N; i++)
> -    s += "-";
> -  s += "| ";
> -  std::stringstream line;
> +    line << '=';
> +  if (n < N)
> +    line << '>';
> +  for (int i = n+1; i < N; i++)
> +    line << ' ';
> +
>    line << std::setiosflags(std::ios::fixed);
>    line << std::setprecision(1);
> -  line << 100.0*p;
> -  s += line.str() + "%";
> -  write(0, s);
> +  line << "] " << 100.0*p << '%';
> +
> +  write(PROGRESS, line.str());
>  }
>  //-----------------------------------------------------------------------------
>  void Logger::set_output_stream(std::ostream& ostream)
> @@ -138,7 +128,7 @@
>    // Print a message
>    std::stringstream line;
>    line << "Elapsed time: " << elapsed_time << " (" << task << ")";
> -  info(line.str(), 1);
> +  info(line.str(), TRACE);
>
>    // Store values for summary
>    map_iterator it = timings.find(task);
> @@ -207,13 +197,13 @@
>  void Logger::__debug(std::string msg) const
>  {
>    std::string s = std::string("Debug: ") + msg;
> -  write(0, s);
> +  write(DEBUG, s);
>  }
>  //-----------------------------------------------------------------------------
>  void Logger::write(int log_level, std::string msg) const
>  {
>    // Check log level
> -  if (!active || log_level > this->log_level)
> +  if (!active || log_level < this->log_level)
>      return;
>
>    // Prefix with process number if running in parallel
>
> === modified file 'dolfin/log/Logger.h'
> --- dolfin/log/Logger.h	2009-07-10 11:29:15 +0000
> +++ dolfin/log/Logger.h	2010-03-23 15:50:40 +0000
> @@ -15,10 +15,10 @@
>  #include <ostream>
>  #include <map>
>  #include <dolfin/common/types.h>
> +#include "LogLevel.h"
>
>  namespace dolfin
>  {
> -
>    class Logger
>    {
>    public:
> @@ -30,10 +30,10 @@
>      ~Logger();
>
>      /// Print message
> -    void info(std::string msg, int log_level = 0) const;
> +    void info(std::string msg, int log_level = INFO) const;
>
>      /// Print underlined message
> -    void info_underline(std::string msg, int log_level = 0) const;
> +    void info_underline(std::string msg, int log_level = INFO) const;
>
>      /// Print warning
>      void warning(std::string msg) const;
> @@ -42,7 +42,7 @@
>      void error(std::string msg) const;
>
>      /// Begin task (increase indentation level)
> -    void begin(std::string msg, int log_level = 0);
> +    void begin(std::string msg, int log_level = PROGRESS);
>
>      /// End task (decrease indentation level)
>      void end();
>
> === modified file 'dolfin/log/Progress.cpp'
> --- dolfin/log/Progress.cpp	2009-07-02 16:25:23 +0000
> +++ dolfin/log/Progress.cpp	2010-03-24 14:50:48 +0000
> @@ -28,8 +28,8 @@
>    // LogManager::logger.progress(title, 0.0);
>    t = time();
>
> -  // When log level is more than 0, progress is always visible
> -  if (LogManager::logger.get_log_level() > 0 )
> +  // When log level is TRACE or lower, always display at least the 100% message
> +  if (LogManager::logger.get_log_level() <= TRACE )
>      always = true;
>  }
>  //-----------------------------------------------------------------------------
> @@ -40,8 +40,8 @@
>    // LogManager::logger.progress(title, 0.0);
>    t = time();
>
> -  // When log level is more than 0, progress is always visible
> -  if (LogManager::logger.get_log_level() > 0 )
> +  // When log level is TRACE or lower, always display at least the 100% message
> +  if (LogManager::logger.get_log_level() <= TRACE )
>      always = true;
>  }
>  //-----------------------------------------------------------------------------
> @@ -71,25 +71,45 @@
>  //-----------------------------------------------------------------------------
>  void Progress::update(double p)
>  {
> +  if (finished)
> +    return;
> +
>    //p = std::max(std::min(p, 1.0), 0.0);
>    //const bool p_check = p - this->p >= p_step - DOLFIN_EPS;
>
>    const double t = time();
> -  const bool t_check = t - this->t >= t_step - DOLFIN_EPS;
> +  const bool t_check = (t - this->t >= t_step - DOLFIN_EPS);
> +  if (t_check) {
> +    // reset time for next update
> +    this->p = p;
> +    this->t = t;
> +  }
> +
> +  bool do_log_update = t_check;
> +
> +  if (t_check && !always && !displayed && p >= 0.7) {
> +    // skip the first update, since it will probably reach 100%
> +    // before the next time t_check is true
> +    do_log_update = false;
> +
> +    // ...but don't skip the next (pretend we displayed this one)
> +    displayed = true;
> +  }
> +
> +  if (p >= 1.0) {
> +    // always display 100% message if a message has already been shown
> +    if (displayed || always)
> +      do_log_update = true;
> +
> +    // ...but don't show more than one
> +    finished = true;
> +  }
>
>    // Only update when the increase is significant
> -  if (t_check || always || (p >= 1.0 && displayed && !finished))
> +  if (do_log_update)
>    {
>      LogManager::logger.progress(title, p);
> -    this->p = p;
> -    this->t = t;
> -    always = false;
>      displayed = true;
>    }
> -
> -  // Update finished flag
> -  if (p >= 1.0)
> -    finished = true;
> -
>  }
>  //-----------------------------------------------------------------------------
>
> === modified file 'dolfin/log/log.cpp'
> --- dolfin/log/log.cpp	2009-12-03 08:48:41 +0000
> +++ dolfin/log/log.cpp	2010-03-23 15:50:40 +0000
> @@ -136,12 +136,12 @@
>    LogManager::logger.logging(active);
>  }
>  //-----------------------------------------------------------------------------
> -void dolfin::set_log_level(uint level)
> +void dolfin::set_log_level(int level)
>  {
>    LogManager::logger.set_log_level(level);
>  }
>  //-----------------------------------------------------------------------------
> -dolfin::uint dolfin::get_log_level()
> +int dolfin::get_log_level()
>  {
>    return LogManager::logger.get_log_level();
>  }
>
> === modified file 'dolfin/log/log.h'
> --- dolfin/log/log.h	2009-12-03 08:48:41 +0000
> +++ dolfin/log/log.h	2010-03-23 15:50:40 +0000
> @@ -12,6 +12,7 @@
>  #include <string>
>  #include <cassert>
>  #include <dolfin/common/types.h>
> +#include "LogLevel.h"
>
>  namespace dolfin
>  {
> @@ -64,10 +65,10 @@
>    void logging(bool active=true);
>
>    /// Set log level
> -  void set_log_level(uint level);
> +  void set_log_level(int level);
>
>    /// Get log level
> -  uint get_log_level();
> +  int get_log_level();
>
>    /// Print summary of timings and tasks, optionally clearing stored timings
>    void summary(bool reset=false);
>
> === modified file 'dolfin/main/SubSystemsManager.cpp'
> --- dolfin/main/SubSystemsManager.cpp	2009-09-23 08:40:36 +0000
> +++ dolfin/main/SubSystemsManager.cpp	2010-03-23 15:50:40 +0000
> @@ -70,7 +70,7 @@
>    if ( sub_systems_manager.petsc_initialized )
>      return;
>
> -  info(1, "Initializing PETSc (ignoring command-line arguments).");
> +  info(TRACE, "Initializing PETSc (ignoring command-line arguments).");
>
>    // Dummy command-line arguments for PETSc. This is needed since
>    // PetscInitializeNoArguments() does not seem to work.
> @@ -95,7 +95,7 @@
>
>    // Print message if PETSc is intialised with command line arguments
>    if (argc > 1)
> -    info(1, "Initializing PETSc with given command-line arguments.");
> +    info(TRACE, "Initializing PETSc with given command-line arguments.");
>
>    // Initialize PETSc
>    PetscInitialize(&argc, &argv, PETSC_NULL, PETSC_NULL);
>
> === modified file 'dolfin/main/init.cpp'
> --- dolfin/main/init.cpp	2009-07-02 13:09:31 +0000
> +++ dolfin/main/init.cpp	2010-03-24 10:33:06 +0000
> @@ -12,7 +12,7 @@
>  //-----------------------------------------------------------------------------
>  void dolfin::dolfin_init(int argc, char* argv[])
>  {
> -  info("Initializing DOLFIN version %s.", DOLFIN_VERSION);
> +  info(PROGRESS, "Initializing DOLFIN version %s.", DOLFIN_VERSION);
>
>  #ifdef HAS_PETSC
>    SubSystemsManager::init_petsc(argc, argv);
>
> === modified file 'dolfin/mesh/BoundaryComputation.cpp'
> --- dolfin/mesh/BoundaryComputation.cpp	2009-11-04 10:52:55 +0000
> +++ dolfin/mesh/BoundaryComputation.cpp	2010-03-23 15:50:40 +0000
> @@ -43,7 +43,7 @@
>    // the boundary. A facet is on the boundary if it is connected to
>    // exactly one cell.
>
> -  info(1, "Computing boundary mesh.");
> +  info(TRACE, "Computing boundary mesh.");
>
>    // Open boundary mesh for editing
>    const uint D = mesh.topology().dim();
>
> === modified file 'dolfin/mesh/LocalMeshCoarsening.cpp'
> --- dolfin/mesh/LocalMeshCoarsening.cpp	2009-10-08 19:11:44 +0000
> +++ dolfin/mesh/LocalMeshCoarsening.cpp	2010-03-24 10:33:06 +0000
> @@ -34,7 +34,7 @@
>                                                          MeshFunction<bool>& cell_marker,
>                                                          bool coarsen_boundary)
>  {
> -  info("Coarsen simplicial mesh by edge collapse.");
> +  info(TRACE, "Coarsen simplicial mesh by edge collapse.");
>
>    // Get size of old mesh
>    //const uint num_vertices = mesh.size(0);
>
> === modified file 'dolfin/mesh/LocalMeshData.cpp'
> --- dolfin/mesh/LocalMeshData.cpp	2009-09-11 09:28:01 +0000
> +++ dolfin/mesh/LocalMeshData.cpp	2010-03-24 10:33:06 +0000
> @@ -176,7 +176,7 @@
>      for (uint p = 0; p < num_processes; p++)
>      {
>        std::pair<uint, uint> local_range = MPI::local_range(p, num_global_vertices);
> -      info("Sending %d vertices to process %d, range is (%d, %d)",
> +      info(PROGRESS, "Sending %d vertices to process %d, range is (%d, %d)",
>             local_range.second - local_range.first, p, local_range.first, local_range.second);
>        for (uint i = local_range.first; i < local_range.second; i++)
>        {
> @@ -209,7 +209,7 @@
>      for (uint p = 0; p < num_processes; p++)
>      {
>        std::pair<uint, uint> local_range = MPI::local_range(p, num_global_cells);
> -      info("Sending %d cells to process %d, range is (%d, %d)",
> +      info(PROGRESS, "Sending %d cells to process %d, range is (%d, %d)",
>             local_range.second - local_range.first, p, local_range.first, local_range.second);
>        for (uint i = local_range.first; i < local_range.second; i++)
>        {
> @@ -276,7 +276,7 @@
>      vertex_coordinates.push_back(coordinates);
>    }
>
> -  info("Received %d vertex coordinates", vertex_coordinates.size());
> +  info(PROGRESS, "Received %d vertex coordinates", vertex_coordinates.size());
>
>  }
>  //-----------------------------------------------------------------------------
> @@ -287,7 +287,7 @@
>    for (uint i = 0; i < values.size(); i++)
>      vertex_indices.push_back(values[i]);
>
> -  info("Received %d vertex indices", vertex_coordinates.size());
> +  info(PROGRESS, "Received %d vertex indices", vertex_coordinates.size());
>  }
>  //-----------------------------------------------------------------------------
>  void LocalMeshData::unpack_cell_vertices(const std::vector<uint>& values)
> @@ -306,6 +306,6 @@
>      cell_vertices.push_back(vertices);
>    }
>
> -  info("Received %d cell vertices", cell_vertices.size());
> +  info(PROGRESS, "Received %d cell vertices", cell_vertices.size());
>  }
>  //-----------------------------------------------------------------------------
>
> === modified file 'dolfin/mesh/LocalMeshRefinement.cpp'
> --- dolfin/mesh/LocalMeshRefinement.cpp	2009-10-08 19:11:44 +0000
> +++ dolfin/mesh/LocalMeshRefinement.cpp	2010-03-24 10:33:06 +0000
> @@ -38,7 +38,7 @@
>                                                      MeshFunction<bool>& cell_marker,
>                                                      bool refine_boundary)
>  {
> -  info("Refining simplicial mesh by edge bisection.");
> +  info(TRACE, "Refining simplicial mesh by edge bisection.");
>
>    // Get size of old mesh
>    const uint num_vertices = mesh.size(0);
> @@ -518,7 +518,7 @@
>      mat = newmesh.data().create_mesh_function("material indicators", newmesh.type().dim());
>      for(dolfin::uint i=0; i< newmesh.num_cells(); i++)
>        (*mat)[i] = (*oldmesh.data().mesh_function("material indicators"))[cell_map[i]];
> -    info("MeshData MeshFunction \"material indicators\" transformed.");
> +    info(TRACE, "MeshData MeshFunction \"material indicators\" transformed.");
>    }
>
>    //Rewrite boundary indicators
> @@ -591,7 +591,7 @@
>        }
>      }
>
> -  info("MeshData \"boundary indicators\" transformed.");
> +  info(TRACE, "MeshData \"boundary indicators\" transformed.");
>    }
>
>  }
>
> === modified file 'dolfin/mesh/Mesh.cpp'
> --- dolfin/mesh/Mesh.cpp	2009-12-16 13:56:35 +0000
> +++ dolfin/mesh/Mesh.cpp	2010-03-24 10:33:06 +0000
> @@ -204,7 +204,7 @@
>  {
>    // FIXME: Move implementation to separate class and just call function here
>
> -  info("No cells marked for coarsening, assuming uniform mesh coarsening.");
> +  info(DEBUG, "No cells marked for coarsening, assuming uniform mesh coarsening.");
>    MeshFunction<bool> cell_marker(*this);
>    cell_marker.init(this->topology().dim());
>    for (CellIterator c(*this); !c.end(); ++c)
>
> === modified file 'dolfin/mesh/MeshPartitioning.cpp'
> --- dolfin/mesh/MeshPartitioning.cpp	2009-10-08 19:11:44 +0000
> +++ dolfin/mesh/MeshPartitioning.cpp	2010-03-24 10:33:06 +0000
> @@ -501,7 +501,7 @@
>    for (uint i = 0; i < entity_indices.size(); ++i)
>    {
>      if (entity_indices[i] < 0)
> -      info("Missing global number for local entity (%d, %d).", d, i);
> +      info(WARNING, "Missing global number for local entity (%d, %d).", d, i);
>      assert(entity_indices[i] >= 0);
>      (*global_entity_indices)[i] = static_cast<uint>(entity_indices[i]);
>    }
> @@ -586,7 +586,7 @@
>                             &ncommonnodes, &nparts,
>                             tpwgts, ubvec, options,
>                             &edgecut, part, &(*comm));
> -  info("Partitioned mesh, edge cut is %d.", edgecut);
> +  info(PROGRESS, "Partitioned mesh, edge cut is %d.", edgecut);
>
>    // Copy mesh_data
>    cell_partition.clear();
>
> === modified file 'dolfin/mesh/RivaraRefinement.cpp'
> --- dolfin/mesh/RivaraRefinement.cpp	2009-10-08 19:11:44 +0000
> +++ dolfin/mesh/RivaraRefinement.cpp	2010-03-24 10:33:06 +0000
> @@ -20,7 +20,7 @@
>  			      MeshFunction<uint>& cell_map,
>  			      std::vector<int>& facet_map)
>  {
> -  info("Refining simplicial mesh by recursive Rivara bisection.");
> +  info(TRACE, "Refining simplicial mesh by recursive Rivara bisection.");
>
>    int dim = mesh.topology().dim();
>
>
> === modified file 'dolfin/mesh/SubDomain.cpp'
> --- dolfin/mesh/SubDomain.cpp	2009-10-08 19:11:44 +0000
> +++ dolfin/mesh/SubDomain.cpp	2010-03-23 15:50:40 +0000
> @@ -38,7 +38,7 @@
>  //-----------------------------------------------------------------------------
>  void SubDomain::mark(MeshFunction<uint>& sub_domains, uint sub_domain) const
>  {
> -  info(1, "Computing sub domain markers for sub domain %d.", sub_domain);
> +  info(TRACE, "Computing sub domain markers for sub domain %d.", sub_domain);
>
>    // Get the dimension of the entities we are marking
>    const uint dim = sub_domains.dim();
>
> === modified file 'dolfin/mesh/UniformMeshRefinement.cpp'
> --- dolfin/mesh/UniformMeshRefinement.cpp	2009-05-02 20:55:48 +0000
> +++ dolfin/mesh/UniformMeshRefinement.cpp	2010-03-23 15:50:40 +0000
> @@ -27,7 +27,7 @@
>  //-----------------------------------------------------------------------------
>  void UniformMeshRefinement::refine_simplex(Mesh& mesh)
>  {
> -  info(1, "Refining simplicial mesh uniformly.");
> +  info(TRACE, "Refining simplicial mesh uniformly.");
>
>    // Generate cell - edge connectivity if not generated
>    mesh.init(mesh.topology().dim(), 1);
>
> === modified file 'dolfin/mesh/UnitSphere.cpp'
> --- dolfin/mesh/UnitSphere.cpp	2009-08-06 17:57:54 +0000
> +++ dolfin/mesh/UnitSphere.cpp	2010-03-24 10:33:06 +0000
> @@ -20,7 +20,7 @@
>    // Receive mesh according to parallel policy
>    if (MPI::is_receiver()) { MeshPartitioning::partition(*this); return; }
>
> -  info("UnitSphere is experimental. It may be of poor quality mesh");
> +  info(WARNING, "UnitSphere is experimental. It may be of poor quality mesh");
>
>    uint ny=nx;
>    uint nz=nx;
>
> === modified file 'dolfin/nls/NewtonSolver.cpp'
> --- dolfin/nls/NewtonSolver.cpp	2009-10-06 19:35:28 +0000
> +++ dolfin/nls/NewtonSolver.cpp	2010-03-24 10:33:06 +0000
> @@ -107,7 +107,7 @@
>    }
>
>    if (newton_converged)
> -    info("Newton solver finished in %d iterations and %d linear solver iterations.",
> +    info(PROGRESS, "Newton solver finished in %d iterations and %d linear solver iterations.",
>              newton_iteration, krylov_iterations);
>    else
>      warning("Newton solver did not converge.");
>
> === modified file 'dolfin/ode/ComplexODE.cpp'
> --- dolfin/ode/ComplexODE.cpp	2009-05-02 20:55:48 +0000
> +++ dolfin/ode/ComplexODE.cpp	2010-03-24 10:33:06 +0000
> @@ -14,7 +14,7 @@
>  ComplexODE::ComplexODE(uint n, real T) : ODE(2*n, T), n(n), j(0.0, 1.0),
>                                             zvalues(0), fvalues(0), yvalues(0)
>  {
> -  info("Creating complex ODE of size %d (%d complex components).", N, n);
> +  info(TRACE, "Creating complex ODE of size %d (%d complex components).", N, n);
>
>    // Initialize complex solution vector and right-hand side
>    zvalues = new complex[n];
>
> === modified file 'dolfin/ode/MonoAdaptivity.cpp'
> --- dolfin/ode/MonoAdaptivity.cpp	2009-09-08 16:38:36 +0000
> +++ dolfin/ode/MonoAdaptivity.cpp	2010-03-24 10:33:06 +0000
> @@ -75,7 +75,7 @@
>      controller.reset(k);
>      _accept = false;
>
> -    //info("e = %.3e  tol = %.3e", error, tol);
> +    //info(DEBUG, "e = %.3e  tol = %.3e", error, tol);
>    }
>  }
>  //-----------------------------------------------------------------------------
>
> === modified file 'dolfin/ode/MultiAdaptiveJacobian.cpp'
> --- dolfin/ode/MultiAdaptiveJacobian.cpp	2009-07-10 12:16:02 +0000
> +++ dolfin/ode/MultiAdaptiveJacobian.cpp	2010-03-24 10:33:06 +0000
> @@ -37,7 +37,7 @@
>    for (uint pos = 0; pos < sum; pos++)
>      Jvalues[pos] = 0.0;
>
> -  info("Generated Jacobian data structure for %d dependencies.", sum);
> +  info(PROGRESS, "Generated Jacobian data structure for %d dependencies.", sum);
>
>    // Compute maximum number of dependencies
>    uint maxsize = 0;
> @@ -83,7 +83,7 @@
>  {
>    // Compute Jacobian at the beginning of the slab
>    double t = to_double(ts.starttime());
> -  //info("Recomputing Jacobian matrix at t = %f.", t);
> +  //info(PROGRESS, "Recomputing Jacobian matrix at t = %f.", t);
>
>    // Compute Jacobian
>    for (uint i = 0; i < ode.size(); i++)
> @@ -96,7 +96,7 @@
>    /*
>    // Compute Jacobian at the end of the slab
>    double t = ts.endtime();
> -  //info("Recomputing Jacobian matrix at t = %f.", t);
> +  //info(PROGRESS, "Recomputing Jacobian matrix at t = %f.", t);
>
>    // Compute Jacobian
>    for (uint i = 0; i < ode.size(); i++)
> @@ -275,7 +275,7 @@
>  	// searching, but we were clever enough to pick out the value
>  	// before when we had the chance... :-)
>  	const double dfdu = Jlookup[dep];
> -	//info("Looks like df_%d/du_%d = %f", i0, i1, dfdu);
> +	//info(DEBUG, "Looks like df_%d/du_%d = %f", i0, i1, dfdu);
>
>  	// Iterate over quadrature points of other element
>  	const double tmp0 = k0 * dfdu;
> @@ -447,7 +447,7 @@
>  	// searching, but we were clever enough to pick out the value
>  	// before when we had the chance... :-)
>  	const double dfdu = Jlookup[dep];
> -	//info("Looks like df_%d/du_%d = %f", i0, i1, dfdu);
> +	//info(DEBUG, "Looks like df_%d/du_%d = %f", i0, i1, dfdu);
>
>  	// Iterate over quadrature points of other element
>  	const double tmp0 = k0 * dfdu;
>
> === modified file 'dolfin/ode/MultiAdaptiveTimeSlab.cpp'
> --- dolfin/ode/MultiAdaptiveTimeSlab.cpp	2009-09-08 16:38:36 +0000
> +++ dolfin/ode/MultiAdaptiveTimeSlab.cpp	2010-03-24 10:33:06 +0000
> @@ -43,7 +43,7 @@
>    real_zero(N, u);
>
>    // Initialize transpose of dependencies if necessary
> -  info("Computing transpose (inverse) of dependency pattern.");
> +  info(TRACE, "Computing transpose (inverse) of dependency pattern.");
>    if (ode.dependencies.sparse() && !ode.transpose.sparse())
>      ode.transpose.transp(ode.dependencies);
>  }
> @@ -100,7 +100,7 @@
>  //-----------------------------------------------------------------------------
>  bool MultiAdaptiveTimeSlab::solve()
>  {
> -  //info("Solving time slab system on [%f, %f].", _a, _b);
> +  //info(TRACE, "Solving time slab system on [%f, %f].", _a, _b);
>
>    // Copy u0 to u. This happens automatically in feval if user has set
>    // dependencies correctly, but you never know...
> @@ -120,7 +120,7 @@
>    //for (uint i = 0; i < N; i++)
>    // {
>    //  real endval = jx[elast[i] * method->nsize() + method->nsize() - 1];
> -  //  info("i = %d: u = %.16e", i, endval);
> +  //  info(DEBUG, "i = %d: u = %.16e", i, endval);
>    // }
>  }
>  //-----------------------------------------------------------------------------
> @@ -418,7 +418,7 @@
>    // Get next available position
>    uint pos = size_e.next++;
>
> -  //info("  Creating element e = %d for i = %d at [%f, %f]", pos, index, a, b);
> +  //info(DEBUG, "  Creating element e = %d for i = %d at [%f, %f]", pos, index, a, b);
>
>    //if ( index == 145 )
>    //  cout << "Modified: " << b - a << endl << endl;
> @@ -456,7 +456,7 @@
>    // Add dependencies to elements that depend on the given element if the
>    // depending elements use larger time steps
>
> -  //info("Checking dependencies to element %d (component %d)", element, index);
> +  //info(TRACE, "Checking dependencies to element %d (component %d)", element, index);
>
>    // Get list of components depending on current component
>    const std::vector<uint>& deps = ode.transpose[i0];
> @@ -486,7 +486,7 @@
>      if ( !within(a0, b0, a1, b1) || s0 == s1 )
>        continue;
>
> -    //info("  Checking element %d (component %d)", e1, i1);
> +    //info(DEBUG, "  Checking element %d (component %d)", e1, i1);
>
>      // Iterate over dofs for element
>      for (uint n = 0; n < method->nsize(); n++)
> @@ -494,7 +494,7 @@
>        //const uint j = j1 + n;
>        const real t = a1 + k1*method->npoint(n);
>
> -      //info("    Checking dof at t = %f", t);
> +      //info(DEBUG, "    Checking dof at t = %f", t);
>
>        // Check if dof is contained in the current element
>        if ( within(t, a0, b0) )
> @@ -528,7 +528,7 @@
>
>    if ( newsize <= size_s.size ) return;
>
> -  //info("Reallocating: ns = %d", newsize);
> +  //info(DEBUG, "Reallocating: ns = %d", newsize);
>
>    Alloc::realloc(&sa, size_s.size, newsize);
>    Alloc::realloc(&sb, size_s.size, newsize);
> @@ -542,7 +542,7 @@
>
>    if ( newsize <= size_e.size ) return;
>
> -  //info("Reallocating: ne = %d", newsize);
> +  //info(DEGUG, "Reallocating: ne = %d", newsize);
>
>    Alloc::realloc(&ei, size_e.size, newsize);
>    Alloc::realloc(&es, size_e.size, newsize);
> @@ -558,7 +558,7 @@
>
>    if ( newsize <= size_j.size ) return;
>
> -  //info("Reallocating: nj = %d", newsize);
> +  //info(DEBUG, "Reallocating: nj = %d", newsize);
>
>    Alloc::realloc(&jx, size_j.size, newsize);
>
> @@ -571,7 +571,7 @@
>
>    if ( newsize <= size_d.size ) return;
>
> -  //info("Reallocating: nd = %d", newsize);
> +  //info(DEBUG, "Reallocating: nd = %d", newsize);
>
>    Alloc::realloc(&de, size_d.size, newsize);
>
>
> === modified file 'dolfin/ode/ODE.cpp'
> --- dolfin/ode/ODE.cpp	2009-09-10 15:24:42 +0000
> +++ dolfin/ode/ODE.cpp	2010-03-24 10:33:06 +0000
> @@ -27,7 +27,7 @@
>  {
>    not_working_in_parallel("ODE solver");
>
> -  info("Creating ODE of size %d.", N);
> +  info(TRACE, "Creating ODE of size %d.", N);
>    parameters = default_parameters();
>
>    #ifdef HAS_GMP
>
> === modified file 'dolfin/ode/ODECollection.cpp'
> --- dolfin/ode/ODECollection.cpp	2009-09-10 12:07:47 +0000
> +++ dolfin/ode/ODECollection.cpp	2010-03-24 10:33:06 +0000
> @@ -14,7 +14,7 @@
>  ODECollection::ODECollection(ODE& ode, uint num_systems)
>    : ode(ode), num_systems(num_systems), states(0)
>  {
> -  info("Creating ODE collection of size %d x %d.", num_systems, ode.size());
> +  info(TRACE, "Creating ODE collection of size %d x %d.", num_systems, ode.size());
>
>    // Allocate state vectors
>    states = new real[num_systems*ode.size()];
>
> === modified file 'dolfin/ode/ODESolver.cpp'
> --- dolfin/ode/ODESolver.cpp	2009-09-10 11:07:52 +0000
> +++ dolfin/ode/ODESolver.cpp	2010-03-24 10:33:06 +0000
> @@ -39,7 +39,7 @@
>    time_stepper.solve();
>
>    // Report elapsed time
> -  info("ODE solution computed in %.3f seconds.", toc());
> +  info(PROGRESS, "ODE solution computed in %.3f seconds.", toc());
>
>    end();
>  }
> @@ -57,7 +57,7 @@
>    u.flush();
>
>    // Report elapsed time
> -  info("ODE solution computed in %.3f seconds.", toc());
> +  info(PROGRESS, "ODE solution computed in %.3f seconds.", toc());
>
>    end();
>  }
>
> === modified file 'dolfin/ode/cGqMethod.cpp'
> --- dolfin/ode/cGqMethod.cpp	2009-09-01 15:30:03 +0000
> +++ dolfin/ode/cGqMethod.cpp	2010-03-24 10:33:06 +0000
> @@ -21,7 +21,7 @@
>  //-----------------------------------------------------------------------------
>  cGqMethod::cGqMethod(uint q) : Method(q, q + 1, q)
>  {
> -  info("Initializing continuous Galerkin method cG(%d).", q);
> +  info(TRACE, "Initializing continuous Galerkin method cG(%d).", q);
>
>    init();
>
>
> === modified file 'dolfin/ode/dGqMethod.cpp'
> --- dolfin/ode/dGqMethod.cpp	2009-09-01 15:30:03 +0000
> +++ dolfin/ode/dGqMethod.cpp	2010-03-24 10:33:06 +0000
> @@ -20,7 +20,7 @@
>  //-----------------------------------------------------------------------------
>  dGqMethod::dGqMethod(unsigned int q) : Method(q, q + 1, q + 1)
>  {
> -  info("Initializing discontinuous Galerkin method dG(%d).", q);
> +  info(TRACE, "Initializing discontinuous Galerkin method dG(%d).", q);
>
>    init();
>
>
> === modified file 'dolfin/parameter/GlobalParameters.cpp'
> --- dolfin/parameter/GlobalParameters.cpp	2009-10-29 09:41:24 +0000
> +++ dolfin/parameter/GlobalParameters.cpp	2010-03-24 10:33:06 +0000
> @@ -70,7 +70,7 @@
>  //-----------------------------------------------------------------------------
>  void GlobalParameters::parse(int argc, char* argv[])
>  {
> -  info("Parsing command-line arguments...");
> +  info(TRACE, "Parsing command-line arguments...");
>
>    // Extract DOLFIN and PETSc arguments
>    std::vector<std::string> args_dolfin;
>
> === modified file 'dolfin/parameter/Parameters.cpp'
> --- dolfin/parameter/Parameters.cpp	2009-12-08 21:18:18 +0000
> +++ dolfin/parameter/Parameters.cpp	2010-03-24 10:33:06 +0000
> @@ -214,7 +214,7 @@
>  //-----------------------------------------------------------------------------
>  void Parameters::parse(int argc, char* argv[])
>  {
> -  info("Parsing command-line arguments...");
> +  info(TRACE, "Parsing command-line arguments...");
>    parse_dolfin(argc, argv);
>  }
>  //-----------------------------------------------------------------------------
>
> === modified file 'dolfin/plot/plot.cpp'
> --- dolfin/plot/plot.cpp	2009-10-07 09:26:57 +0000
> +++ dolfin/plot/plot.cpp	2010-03-24 10:33:06 +0000
> @@ -29,7 +29,7 @@
>    if (dolfin::MPI::num_processes() > 1)
>    {
>      if (dolfin::MPI::process_number() == 0)
> -      info("On screen plotting from C++ not yet working in parallel.");
> +      warning("On screen plotting from C++ not yet working in parallel.");
>      return;
>    }
>
>
> === modified file 'dolfin/swig/log_post.i'
> --- dolfin/swig/log_post.i	2009-09-11 05:53:28 +0000
> +++ dolfin/swig/log_post.i	2010-03-23 15:50:40 +0000
> @@ -53,6 +53,11 @@
>      __debug(file, line, func, message)
>
>  def info(*args):
> +    if args and isinstance(args[0], int):
> +        if args[0] < get_log_level():
> +            return
> +        args = args[1:]
> +
>      if len(args) > 0 and isinstance(args[0],(Variable,Parameters)):
>          if len(args) > 1:
>              _info(args[0].str(*args[1:]))
>
> === modified file 'dolfin/swig/parameter_post.i'
> --- dolfin/swig/parameter_post.i	2009-12-17 03:34:54 +0000
> +++ dolfin/swig/parameter_post.i	2010-03-23 15:50:40 +0000
> @@ -18,6 +18,14 @@
>  %extend dolfin::Parameter
>  {
>  %pythoncode%{
> +def warn_once(self, msg):
> +    cls = self.__class__
> +    if not hasattr(cls, '_warned'):
> +        cls._warned = set()
> +    if not msg in cls._warned:
> +        cls._warned.add(msg)
> +        print msg
> +
>  def value(self):
>      val_type = self.type_str()
>      if val_type == "string":
> @@ -27,9 +35,10 @@
>      elif val_type == "bool":
>          return bool(self)
>      elif val_type == "real":
> -        if has_gmp():
> +        from logging import DEBUG
> +        if get_log_level() <= DEBUG and has_gmp():
>              # FIXME: Is it possible to convert real to some high-precision Python type?
> -            print "Warning: Converting real-valued parameter to double, might loose precision."
> +            self.warn_once("Warning: Converting real-valued parameter '%s' to double, might lose precision."%self.key())
>          return float(self)
>      else:
>          raise TypeError, "unknown value type '%s' of parameter '%s'"%(val_type, self.key())
> @@ -49,9 +58,10 @@
>      elif val_type == "bool":
>          return
>      elif val_type == "real":
> -        if has_gmp():
> +        from logging import DEBUG
> +        if get_log_level() <= DEBUG and has_gmp():
>              # FIXME: Is it possible to convert real to some high-precision Python type?
> -            print "Warning: Converting real-valued parameter to double, might loose precision."
> +            self.warn_once("Warning: Converting real-valued parameter '%s' to double, might lose precision."%self.key())
>          local_range = self._get_real_range()
>          if local_range[0] == 0 and local_range[0] == local_range[0]:
>              return
>
> # Begin bundle
> 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
> 8+CjT77OQJLhvDx/unIcx/8XckU4UJASNWGt
>





> _______________________________________________
> Mailing list: https://launchpad.net/~dolfin
> Post to     : dolfin@xxxxxxxxxxxxxxxxxxx
> Unsubscribe : https://launchpad.net/~dolfin
> More help   : https://help.launchpad.net/ListHelp

Attachment: signature.asc
Description: Digital signature


Follow ups

References