//!
    virtual void CallBuild(Level& requestedLevel) const {
      int levelID = requestedLevel.GetLevelID();

#ifdef HAVE_MUELU_DEBUG
      // We cannot call Build method twice for the same level, but we can call it multiple times for different levels
      TEUCHOS_TEST_FOR_EXCEPTION((multipleCallCheck_ == ENABLED) && (multipleCallCheckGlobal_ == ENABLED) && (lastLevelID_ == levelID),
                                 Exceptions::RuntimeError,
                                 this->ShortClassName() << "::Build() called twice for the same level (levelID=" << levelID
                                 << "). This is likely due to a configuration error.");
      if (multipleCallCheck_ == FIRSTCALL)
        multipleCallCheck_ = ENABLED;

      lastLevelID_ = levelID;
#endif
      TEUCHOS_TEST_FOR_EXCEPTION(requestedLevel.GetPreviousLevel() == Teuchos::null, Exceptions::RuntimeError, "LevelID = " << levelID);

#ifdef HAVE_MUELU_TIMER_SYNCHRONIZATION
      RCP<const Teuchos::Comm<int> > comm = requestedLevel.GetComm();
      if (comm.is_null()) {
        // Some factories are called before we constructed Ac, and therefore,
        // before we set the level communicator. For such factories we can get
        // the comm from the previous level, as all processes go there
        RCP<Level>& prevLevel = requestedLevel.GetPreviousLevel();
        if (!prevLevel.is_null())
          comm = prevLevel->GetComm();
      }

      // Synchronization timer
      std::string syncTimer = this->ShortClassName() + ": Build sync (level=" + toString(requestedLevel.GetLevelID()) + ")";
      if (!comm.is_null()) {
        TimeMonitor timer(*this, syncTimer);
        comm->barrier();
      }
#endif

      Build(*requestedLevel.GetPreviousLevel(), requestedLevel);

#ifdef HAVE_MUELU_TIMER_SYNCHRONIZATION
      // Synchronization timer
      if (!comm.is_null()) {
        TimeMonitor timer(*this, syncTimer);
        comm->barrier();
      }
#endif

      GetOStream(Test) << *RemoveFactoriesFromList(GetParameterList()) << std::endl;
    }
  void SmootherFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::BuildSmoother(Level& currentLevel, PreOrPost const preOrPost) const {
    // SmootherFactory is quite tricky because of the fact that one of the smoother prototypes may be zero.
    // The challenge is that we have no way of knowing how user uses this factory. For instance, lets say
    // user wants to use s1 prototype as a presmoother, and s2 as a postsmoother. He could do:
    //   (a) create SmootherFactory(s1, s2), or
    //   (b) create SmootherFactory(s1, null) and SmootherFactory(null, s2)
    // It may also happen that somewhere somebody set presmoother factory = postsmoother factory = (a)
    // How do you do DeclareInput in this case? It could easily introduce a bug if a user does not check
    // whether presmoother = postsmoother. A buggy code could look like that:
    //   RCP<SmootherFactory> s = rcp(new SmootherFactory(s1,s2));
    //   level.Request("PreSmoother",  s.get());
    //   level.Request("PostSmoother", s.get());
    //   Get<RCP<SmootherBase> > pre  = Get<RCP<SmootherBase> >("PreSmoother",  s.get());
    //   Get<RCP<SmootherBase> > post = Get<RCP<SmootherBase> >("PostSmoother", s.get());
    // This code would call DeclareInput in request mode twice, but as the Build method generates both Pre and Post
    // smoothers, it would call DelcareInput in release mode only once, leaving requests.
    // This code has another problem if s2 = Teuchos::null. In that case, despite the request for PostSmoother, the factory
    // would not generate one, and second Get would throw. The real issue here is that given a Factory pointer
    // there is no way to be sure that this factory would generate any of "PreSmoother" or "PostSmoother", unless you are
    // able to cast it to SmootherFactory, do GetPrototypes and to check whether any of those is Teuchos::null.

    const Teuchos::ParameterList& pL = GetParameterList();

    RCP<SmootherPrototype> preSmoother, postSmoother;
    ParameterList preSmootherParams, postSmootherParams;

    if ((preOrPost & PRE) && !preSmootherPrototype_.is_null()) {

      if (currentLevel.IsAvailable("PreSmoother data", this))
        preSmoother = currentLevel.Get<RCP<SmootherPrototype> >("PreSmoother data", this);
      else
        preSmoother = preSmootherPrototype_->Copy();

      int oldRank = -1;
      if (!currentLevel.GetComm().is_null())
        oldRank = preSmoother->SetProcRankVerbose(currentLevel.GetComm()->getRank());

      preSmoother->Setup(currentLevel);
      preSmootherParams = preSmoother->GetParameterList();

      if (oldRank != -1)
        preSmoother->SetProcRankVerbose(oldRank);

      currentLevel.Set<RCP<SmootherBase> >("PreSmoother", preSmoother, this);

      if (pL.get<bool>("keep smoother data"))
        Set(currentLevel, "PreSmoother data", preSmoother);
    }

    if ((preOrPost & POST) && !postSmootherPrototype_.is_null()) {
      if (preOrPost == BOTH && preSmootherPrototype_ == postSmootherPrototype_) {
        // Simple reuse
        // Same prototypes for pre- and post-smoothers mean that we only need to call Setup only once
        postSmoother = preSmoother;

        //               else if (preOrPost == BOTH &&
        //                        preSmootherPrototype_ != Teuchos::null &&
        //                        preSmootherPrototype_->GetType() == postSmootherPrototype_->GetType()) {

        //               // More complex reuse case: need implementation of CopyParameters() and a smoothers smart enough to know when parameters affect the setup phase.

        //               // YES: post-smoother == pre-smoother
        //               // => copy the pre-smoother to avoid the setup phase of the post-smoother.
        //               postSmoother = preSmoother->Copy();
        //               // If the post-smoother parameters are different from
        //               // pre-smoother, the parameters stored in the post-smoother
        //               // prototype are copied in the new post-smoother object.
        //               postSmoother->CopyParameters(postSmootherPrototype_);
        //               // If parameters don't influence the Setup phase (it is the case
        //               // for Jacobi, Chebyshev...), PostSmoother is already setup. Nothing
        //               // more to do. In the case of ILU, parameters of the smoother
        //               // are in fact the parameters of the Setup phase. The call to
        //               // CopyParameters resets the smoother (only if parameters are
        //               // different) and we must call Setup() again.
        //               postSmoother->Setup(currentLevel);
        //               }

        //               // TODO: if CopyParameters do not exist, do setup twice.

      } else {

        if (currentLevel.IsAvailable("PostSmoother data", this)) {
          postSmoother = currentLevel.Get<RCP<SmootherPrototype> >("PostSmoother data", this);
        } else {
          // No reuse:
          //  - either we only do postsmoothing without any presmoothing
          //  - or our postsmoother is different from presmoother
          postSmoother = postSmootherPrototype_->Copy();
        }

        int oldRank = -1;
        if (!currentLevel.GetComm().is_null())
          oldRank = postSmoother->SetProcRankVerbose(GetProcRankVerbose());

        postSmoother->Setup(currentLevel);
        postSmootherParams = postSmoother->GetParameterList();

        if (oldRank != -1)
          postSmoother->SetProcRankVerbose(oldRank);
      }

      currentLevel.Set<RCP<SmootherBase> >("PostSmoother", postSmoother, this);

      if (pL.get<bool>("keep smoother data"))
        Set(currentLevel, "PostSmoother data", preSmoother);
    }

    ParameterList& paramList = const_cast<ParameterList&>(this->GetParameterList());
    if (postSmoother == preSmoother && !preSmoother.is_null()) {
      paramList.sublist("smoother", false) = preSmoother->GetParameterList();

    } else {
      if (!preSmoother.is_null())
        paramList.sublist("presmoother", false) = preSmootherParams;

      if (!postSmoother.is_null())
        paramList.sublist("postsmoother", false) = postSmootherParams;
    }

  } // Build()