dolfin team mailing list archive
-
dolfin team
-
Mailing list archive
-
Message #18007
Re: [jobh@xxxxxxxxx: Fwd: Logging]
-
To:
DOLFIN Mailing List <dolfin@xxxxxxxxxxxxxxxxxxx>
-
From:
Anders Logg <logg@xxxxxxxxx>
-
Date:
Mon, 5 Apr 2010 19:28:03 +0200
-
In-reply-to:
<20100326114319.GE12279@olorin>
-
User-agent:
Mutt/1.5.20 (2009-06-14)
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