MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_IfpackSmoother.cpp
Go to the documentation of this file.
1// @HEADER
2//
3// ***********************************************************************
4//
5// MueLu: A package for multigrid based preconditioning
6// Copyright 2012 Sandia Corporation
7//
8// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9// the U.S. Government retains certain rights in this software.
10//
11// Redistribution and use in source and binary forms, with or without
12// modification, are permitted provided that the following conditions are
13// met:
14//
15// 1. Redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer.
17//
18// 2. Redistributions in binary form must reproduce the above copyright
19// notice, this list of conditions and the following disclaimer in the
20// documentation and/or other materials provided with the distribution.
21//
22// 3. Neither the name of the Corporation nor the names of the
23// contributors may be used to endorse or promote products derived from
24// this software without specific prior written permission.
25//
26// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37//
38// Questions? Contact
39// Jonathan Hu (jhu@sandia.gov)
40// Andrey Prokopenko (aprokop@sandia.gov)
41// Ray Tuminaro (rstumin@sandia.gov)
42//
43// ***********************************************************************
44//
45// @HEADER
46#include "MueLu_ConfigDefs.hpp"
47
48#if defined(HAVE_MUELU_EPETRA) && defined(HAVE_MUELU_IFPACK)
49#include <Ifpack.h>
50#include <Ifpack_Chebyshev.h>
51#include "Xpetra_MultiVectorFactory.hpp"
52
54
55#include "MueLu_Level.hpp"
56#include "MueLu_Utilities.hpp"
57#include "MueLu_Monitor.hpp"
58#include "MueLu_Aggregates.hpp"
59
60
61namespace MueLu {
62
63 template <class Node>
64 IfpackSmoother<Node>::IfpackSmoother(std::string const & type, Teuchos::ParameterList const & paramList, LO const &overlap)
65 : type_(type), overlap_(overlap)
66 {
67 this->declareConstructionOutcome(false, "");
68 SetParameterList(paramList);
69 }
70
71 template <class Node>
72 void IfpackSmoother<Node>::SetParameterList(const Teuchos::ParameterList& paramList) {
74
76 // It might be invalid to change parameters after the setup, but it depends entirely on Ifpack implementation.
77 // TODO: I don't know if Ifpack returns an error code or exception or ignore parameters modification in this case...
78 prec_->SetParameters(const_cast<ParameterList&>(this->GetParameterList()));
79 }
80 }
81
82 template <class Node>
83 void IfpackSmoother<Node>::SetPrecParameters(const Teuchos::ParameterList& list) const {
84 ParameterList& paramList = const_cast<ParameterList&>(this->GetParameterList());
85 paramList.setParameters(list);
86
87 RCP<ParameterList> precList = this->RemoveFactoriesFromList(this->GetParameterList());
88
89 prec_->SetParameters(*precList);
90
91 // We would like to have the following line here:
92 // paramList.setParameters(*precList);
93 // For instance, if Ifpack sets somem parameters internally, we would like to have
94 // them listed when we call this->GetParameterList()
95 // But because of the way Ifpack handles the list, we cannot do that.
96 // The bad scenario goes like this:
97 // * SmootherFactory calls Setup
98 // * Setup calls SetPrecParameters
99 // * We call prec_->SetParameters(*precList)
100 // This actually updates the internal parameter list with default prec_ parameters
101 // This means that we get a parameter ("chebyshev: max eigenvalue", -1) in the list
102 // * Setup calls prec_->Compute()
103 // Here we may compute the max eigenvalue, but we get no indication of this. If we
104 // do compute it, our parameter list becomes outdated
105 // * SmootherFactory calls Apply
106 // * Apply constructs a list with a list with an entry "chebyshev: zero starting solution"
107 // * We call prec_->SetParameters(*precList)
108 // The last call is the problem. At this point, we have a list with an outdated entry
109 // "chebyshev: max eigenvalue", but prec_ uses this entry and replaces the computed max
110 // eigenvalue with the one from the list, resulting in -1.0 eigenvalue.
111 //
112 // Ifpack2 does not have this problem, as it does not populate the list with new entries
113 }
114
115 template <class Node>
116 void IfpackSmoother<Node>::DeclareInput(Level &currentLevel) const {
117 this->Input(currentLevel, "A");
118
119 if (type_ == "LINESMOOTHING_BANDED_RELAXATION" ||
120 type_ == "LINESMOOTHING_BANDED RELAXATION" ||
121 type_ == "LINESMOOTHING_BANDEDRELAXATION" ||
122 type_ == "LINESMOOTHING_BLOCK_RELAXATION" ||
123 type_ == "LINESMOOTHING_BLOCK RELAXATION" ||
124 type_ == "LINESMOOTHING_BLOCKRELAXATION") {
125 this->Input(currentLevel, "CoarseNumZLayers"); // necessary for fallback criterion
126 this->Input(currentLevel, "LineDetection_VertLineIds"); // necessary to feed block smoother
127 } // if (type_ == "LINESMOOTHING_BANDEDRELAXATION")
128 else if (type_ == "AGGREGATE")
129 {
130 // Aggregate smoothing needs aggregates
131 this->Input(currentLevel,"Aggregates");
132 }
133
134 }
135
136 template <class Node>
137 void IfpackSmoother<Node>::Setup(Level &currentLevel) {
138 FactoryMonitor m(*this, "Setup Smoother", currentLevel);
139 if (SmootherPrototype::IsSetup() == true)
140 this->GetOStream(Warnings0) << "MueLu::IfpackSmoother::Setup(): Setup() has already been called" << std::endl;
141
142 A_ = Factory::Get< RCP<Matrix> >(currentLevel, "A");
143
144 double lambdaMax = -1.0;
145 if (type_ == "Chebyshev") {
146 std::string maxEigString = "chebyshev: max eigenvalue";
147 std::string eigRatioString = "chebyshev: ratio eigenvalue";
148
149 try {
150 lambdaMax = Teuchos::getValue<Scalar>(this->GetParameter(maxEigString));
151 this->GetOStream(Statistics1) << maxEigString << " (cached with smoother parameter list) = " << lambdaMax << std::endl;
152
153 } catch (Teuchos::Exceptions::InvalidParameterName&) {
154 lambdaMax = A_->GetMaxEigenvalueEstimate();
155
156 if (lambdaMax != -1.0) {
157 this->GetOStream(Statistics1) << maxEigString << " (cached with matrix) = " << lambdaMax << std::endl;
158 this->SetParameter(maxEigString, ParameterEntry(lambdaMax));
159 }
160 }
161
162 // Calculate the eigenvalue ratio
163 const Scalar defaultEigRatio = 20;
164
165 Scalar ratio = defaultEigRatio;
166 try {
167 ratio = Teuchos::getValue<Scalar>(this->GetParameter(eigRatioString));
168
169 } catch (Teuchos::Exceptions::InvalidParameterName&) {
170 this->SetParameter(eigRatioString, ParameterEntry(ratio));
171 }
172
173 if (currentLevel.GetLevelID()) {
174 // Update ratio to be
175 // ratio = max(number of fine DOFs / number of coarse DOFs, defaultValue)
176 //
177 // NOTE: We don't need to request previous level matrix as we know for sure it was constructed
178 RCP<const Matrix> fineA = currentLevel.GetPreviousLevel()->Get<RCP<Matrix> >("A");
179 size_t nRowsFine = fineA->getGlobalNumRows();
180 size_t nRowsCoarse = A_->getGlobalNumRows();
181
182 ratio = std::max(ratio, as<Scalar>(nRowsFine)/nRowsCoarse);
183
184 this->GetOStream(Statistics1) << eigRatioString << " (computed) = " << ratio << std::endl;
185 this->SetParameter(eigRatioString, ParameterEntry(ratio));
186 }
187 } // if (type_ == "Chebyshev")
188
189 if (type_ == "LINESMOOTHING_BANDED_RELAXATION" ||
190 type_ == "LINESMOOTHING_BANDED RELAXATION" ||
191 type_ == "LINESMOOTHING_BANDEDRELAXATION" ||
192 type_ == "LINESMOOTHING_BLOCK_RELAXATION" ||
193 type_ == "LINESMOOTHING_BLOCK RELAXATION" ||
194 type_ == "LINESMOOTHING_BLOCKRELAXATION" ) {
195 ParameterList& myparamList = const_cast<ParameterList&>(this->GetParameterList());
196
197 LO CoarseNumZLayers = currentLevel.Get<LO>("CoarseNumZLayers",Factory::GetFactory("CoarseNumZLayers").get());
198 if (CoarseNumZLayers > 0) {
199 Teuchos::ArrayRCP<LO> TVertLineIdSmoo = currentLevel.Get< Teuchos::ArrayRCP<LO> >("LineDetection_VertLineIds", Factory::GetFactory("LineDetection_VertLineIds").get());
200
201 // determine number of local parts
202 LO maxPart = 0;
203 for(size_t k = 0; k < Teuchos::as<size_t>(TVertLineIdSmoo.size()); k++) {
204 if(maxPart < TVertLineIdSmoo[k]) maxPart = TVertLineIdSmoo[k];
205 }
206
207 size_t numLocalRows = A_->getLocalNumRows();
208 TEUCHOS_TEST_FOR_EXCEPTION(numLocalRows % TVertLineIdSmoo.size() != 0, Exceptions::RuntimeError, "MueLu::Ifpack2Smoother::Setup(): the number of local nodes is incompatible with the TVertLineIdsSmoo.");
209
210 if (numLocalRows == Teuchos::as<size_t>(TVertLineIdSmoo.size())) {
211 myparamList.set("partitioner: type","user");
212 myparamList.set("partitioner: map",&(TVertLineIdSmoo[0]));
213 myparamList.set("partitioner: local parts",maxPart+1);
214 } else {
215 // we assume a constant number of DOFs per node
216 size_t numDofsPerNode = numLocalRows / TVertLineIdSmoo.size();
217
218 // Create a new Teuchos::ArrayRCP<LO> of size numLocalRows and fill it with the corresponding information
219 Teuchos::ArrayRCP<LO> partitionerMap(numLocalRows, Teuchos::OrdinalTraits<LocalOrdinal>::invalid());
220 for (size_t blockRow = 0; blockRow < Teuchos::as<size_t>(TVertLineIdSmoo.size()); ++blockRow)
221 for (size_t dof = 0; dof < numDofsPerNode; dof++)
222 partitionerMap[blockRow * numDofsPerNode + dof] = TVertLineIdSmoo[blockRow];
223 myparamList.set("partitioner: type","user");
224 myparamList.set("partitioner: map",&(partitionerMap[0]));
225 myparamList.set("partitioner: local parts",maxPart + 1);
226 }
227
228 if (type_ == "LINESMOOTHING_BANDED_RELAXATION" ||
229 type_ == "LINESMOOTHING_BANDED RELAXATION" ||
230 type_ == "LINESMOOTHING_BANDEDRELAXATION")
231 type_ = "block relaxation";
232 else
233 type_ = "block relaxation";
234 } else {
235 // line detection failed -> fallback to point-wise relaxation
236 this->GetOStream(Runtime0) << "Line detection failed: fall back to point-wise relaxation" << std::endl;
237 myparamList.remove("partitioner: type",false);
238 myparamList.remove("partitioner: map", false);
239 myparamList.remove("partitioner: local parts",false);
240 type_ = "point relaxation stand-alone";
241 }
242
243 } // if (type_ == "LINESMOOTHING_BANDEDRELAXATION")
244
245 if(type_ == "AGGREGATE") {
246 SetupAggregate(currentLevel);
247 }
248
249 else {
250 // If we're using a linear partitioner and haven't set the # local parts, set it to match the operator's block size
251 ParameterList precList = this->GetParameterList();
252 if(precList.isParameter("partitioner: type") && precList.get<std::string>("partitioner: type") == "linear" &&
253 !precList.isParameter("partitioner: local parts")) {
254 precList.set("partitioner: local parts", (int)A_->getLocalNumRows() / A_->GetFixedBlockSize());
255 }
256
257
258 RCP<Epetra_CrsMatrix> epA = Utilities::Op2NonConstEpetraCrs(A_);
259
260 Ifpack factory;
261 prec_ = rcp(factory.Create(type_, &(*epA), overlap_));
262 TEUCHOS_TEST_FOR_EXCEPTION(prec_.is_null(), Exceptions::RuntimeError, "Could not create an Ifpack preconditioner with type = \"" << type_ << "\"");
263 SetPrecParameters();
264 prec_->Compute();
265 }
266
268
269 if (type_ == "Chebyshev" && lambdaMax == -1.0) {
270 Teuchos::RCP<Ifpack_Chebyshev> chebyPrec = rcp_dynamic_cast<Ifpack_Chebyshev>(prec_);
271 if (chebyPrec != Teuchos::null) {
272 lambdaMax = chebyPrec->GetLambdaMax();
273 A_->SetMaxEigenvalueEstimate(lambdaMax);
274 this->GetOStream(Statistics1) << "chebyshev: max eigenvalue (calculated by Ifpack)" << " = " << lambdaMax << std::endl;
275 }
276 TEUCHOS_TEST_FOR_EXCEPTION(lambdaMax == -1.0, Exceptions::RuntimeError, "MueLu::IfpackSmoother::Setup(): no maximum eigenvalue estimate");
277 }
278
279 this->GetOStream(Statistics1) << description() << std::endl;
280 }
281
282
283 template <class Node>
285
286 ParameterList& paramList = const_cast<ParameterList&>(this->GetParameterList());
287
288 if (this->IsSetup() == true) {
289 this->GetOStream(Warnings0) << "MueLu::Ifpack2moother::SetupAggregate(): Setup() has already been called" << std::endl;
290 this->GetOStream(Warnings0) << "MueLu::IfpackSmoother::SetupAggregate(): reuse of this type is not available, reverting to full construction" << std::endl;
291 }
292
293 this->GetOStream(Statistics0) << "IfpackSmoother: Using Aggregate Smoothing"<<std::endl;
294
295 RCP<Aggregates> aggregates = Factory::Get<RCP<Aggregates> >(currentLevel,"Aggregates");
296 RCP<const LOMultiVector> vertex2AggId = aggregates->GetVertex2AggId();
297 ArrayRCP<LO> aggregate_ids = rcp_const_cast<LOMultiVector>(vertex2AggId)->getDataNonConst(0);
298 ArrayRCP<LO> dof_ids;
299
300 // We need to unamalgamate, if the FixedBlockSize > 1
301 if(A_->GetFixedBlockSize() > 1) {
302 // NOTE: We're basically going to have to leave a deallocated pointer hanging out
303 // in the paramList object (and inside the partitioner). This never gets
304 // use again after Compute() gets called, so this is OK, but I'm still leaving
305 // this note here in case it bites us again later.
306 LO blocksize = (LO) A_->GetFixedBlockSize();
307 dof_ids.resize(aggregate_ids.size() * blocksize);
308 for(LO i=0; i<(LO)aggregate_ids.size(); i++) {
309 for(LO j=0; j<(LO)blocksize; j++)
310 dof_ids[i*blocksize+j] = aggregate_ids[i];
311 }
312 }
313 else {
314 dof_ids = aggregate_ids;
315 }
316
317 paramList.set("partitioner: map", dof_ids.getRawPtr());
318 paramList.set("partitioner: type", "user");
319 paramList.set("partitioner: overlap", 0);
320 paramList.set("partitioner: local parts", (int)aggregates->GetNumAggregates());
321 // In case of Dirichlet nodes
322 paramList.set("partitioner: keep singletons",true);
323
324 RCP<Epetra_CrsMatrix> A = Utilities::Op2NonConstEpetraCrs(A_);
325 type_ = "block relaxation stand-alone";
326
327 Ifpack factory;
328 prec_ = rcp(factory.Create(type_, &(*A), overlap_));
329 TEUCHOS_TEST_FOR_EXCEPTION(prec_.is_null(), Exceptions::RuntimeError, "Could not create an Ifpack preconditioner with type = \"" << type_ << "\"");
330 SetPrecParameters();
331
332 int rv = prec_->Compute();
333 TEUCHOS_TEST_FOR_EXCEPTION(rv, Exceptions::RuntimeError, "Ifpack preconditioner with type = \"" << type_ << "\" Compute() call failed.");
334
335 }
336
337
338 template <class Node>
339 void IfpackSmoother<Node>::Apply(MultiVector& X, const MultiVector& B, bool InitialGuessIsZero) const {
340 TEUCHOS_TEST_FOR_EXCEPTION(SmootherPrototype::IsSetup() == false, Exceptions::RuntimeError, "MueLu::IfpackSmoother::Apply(): Setup() has not been called");
341
342
343 // Forward the InitialGuessIsZero option to Ifpack
344 Teuchos::ParameterList paramList;
345 bool supportInitialGuess = false;
346 if (type_ == "Chebyshev") {
347 paramList.set("chebyshev: zero starting solution", InitialGuessIsZero);
348 supportInitialGuess = true;
349
350 } else if (type_ == "point relaxation stand-alone") {
351 paramList.set("relaxation: zero starting solution", InitialGuessIsZero);
352 supportInitialGuess = true;
353 }
354
355 SetPrecParameters(paramList);
356
357 // Apply
358 if (InitialGuessIsZero || supportInitialGuess) {
361
362 prec_->ApplyInverse(epB, epX);
363
364 } else {
365 RCP<MultiVector> Residual = Utilities::Residual(*A_, X, B);
366 RCP<MultiVector> Correction = MultiVectorFactory::Build(A_->getDomainMap(), X.getNumVectors());
367
369 const Epetra_MultiVector& epB = Utilities::MV2EpetraMV(*Residual);
370
371 prec_->ApplyInverse(epB, epX);
372
373 X.update(1.0, *Correction, 1.0);
374 }
375 }
376
377 template <class Node>
378 RCP<MueLu::SmootherPrototype<double, int, int, Node> > IfpackSmoother<Node>::Copy() const {
379 RCP<IfpackSmoother<Node> > smoother = rcp(new IfpackSmoother<Node>(*this) );
380 smoother->SetParameterList(this->GetParameterList());
381 return Teuchos::rcp_dynamic_cast<MueLu::SmootherPrototype<double, int, int, Node> >(smoother);
382 }
383
384 template <class Node>
386 std::ostringstream out;
387 // The check "GetVerbLevel() == Test" is to avoid
388 // failures in the EasyInterface test.
389 if (prec_ == Teuchos::null || this->GetVerbLevel() == InterfaceTest) {
391 out << "{type = " << type_ << "}";
392 } else {
393 out << prec_->Label();
394 }
395 return out.str();
396 }
397
398 template <class Node>
399 void IfpackSmoother<Node>::print(Teuchos::FancyOStream &out, const VerbLevel verbLevel) const {
401
402 if (verbLevel & Parameters0)
403 out0 << "Prec. type: " << type_ << std::endl;
404
405 if (verbLevel & Parameters1) {
406 out0 << "Parameter list: " << std::endl;
407 Teuchos::OSTab tab2(out);
408 out << this->GetParameterList();
409 out0 << "Overlap: " << overlap_ << std::endl;
410 }
411
412 if (verbLevel & External)
413 if (prec_ != Teuchos::null) {
414 Teuchos::OSTab tab2(out);
415 out << *prec_ << std::endl;
416 }
417
418 if (verbLevel & Debug) {
419 out0 << "IsSetup: " << Teuchos::toString(SmootherPrototype::IsSetup()) << std::endl
420 << "-" << std::endl
421 << "RCP<A_>: " << A_ << std::endl
422 << "RCP<prec_>: " << prec_ << std::endl;
423 }
424 }
425
426 template <class Node>
428 // FIXME: This is a placeholder
429 return Teuchos::OrdinalTraits<size_t>::invalid();
430 }
431
432
433} // namespace MueLu
434
435// The IfpackSmoother is only templated on the Node, since it is an Epetra only object
436// Therefore we do not need the full ETI instantiations as we do for the other MueLu
437// objects which are instantiated on all template parameters.
438#if defined(HAVE_MUELU_EPETRA)
440#endif
441
442#endif
#define MUELU_DESCRIBE
Helper macro for implementing Describable::describe() for BaseClass objects.
Ifpack_Preconditioner * Create(const std::string PrecType, Epetra_RowMatrix *Matrix, const int overlap=0, bool overrideSerialDefault=false)
virtual std::string description() const
Return a simple one-line description of this object.
Exception throws to report errors in the internal logical of the program.
Timer to be used in factories. Similar to Monitor but with additional timers.
const RCP< const FactoryBase > GetFactory(const std::string &varName) const
Default implementation of FactoryAcceptor::GetFactory()
Class that encapsulates Ifpack smoothers.
void Apply(MultiVector &X, const MultiVector &B, bool InitialGuessIsZero=false) const
Apply the preconditioner.
void SetPrecParameters(const Teuchos::ParameterList &list=Teuchos::ParameterList()) const
IfpackSmoother(std::string const &type, Teuchos::ParameterList const &paramList=Teuchos::ParameterList(), LO const &overlap=0)
Constructor.
void print(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
Print the object with some verbosity level to an FancyOStream object.
std::string description() const
Return a simple one-line description of this object.
void Setup(Level &currentLevel)
Set up the smoother.
RCP< SmootherPrototype > Copy() const
void DeclareInput(Level &currentLevel) const
Input.
size_t getNodeSmootherComplexity() const
Get a rough estimate of cost per iteration.
void SetupAggregate(Level &currentLevel)
void SetParameterList(const Teuchos::ParameterList &paramList)
Set parameters from a parameter list and return with default values.
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
RCP< Level > & GetPreviousLevel()
Previous level.
int GetLevelID() const
Return level number.
Definition: MueLu_Level.cpp:76
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access)....
virtual void SetParameterList(const Teuchos::ParameterList &paramList)=0
Set parameters from a parameter list and return with default values.
void declareConstructionOutcome(bool fail, std::string msg)
bool IsSetup() const
Get the state of a smoother prototype.
static RCP< Epetra_MultiVector > MV2NonConstEpetraMV(RCP< Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > vec)
static RCP< Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Residual(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &X, const Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &RHS)
static RCP< Epetra_CrsMatrix > Op2NonConstEpetraCrs(RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Op)
static RCP< const Epetra_MultiVector > MV2EpetraMV(RCP< Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > const vec)
Helper utility to pull out the underlying Epetra objects from an Xpetra object.
Namespace for MueLu classes and methods.
@ Warnings0
Important warning messages (one line)
@ Debug
Print additional debugging information.
@ Statistics1
Print more statistics.
@ External
Print external lib objects.
@ Runtime0
One-liner description of what is happening.
@ Parameters0
Print class parameters.
@ Statistics0
Print statistics that do not involve significant additional computation.
@ Parameters1
Print class parameters (more parameters, more verbose)