예제 #1
0
void
LSQRSolMgr<ScalarType,MV,OP,false>::
setParameters (const Teuchos::RCP<Teuchos::ParameterList> &params)
{
    using Teuchos::isParameterType;
    using Teuchos::getParameter;
    using Teuchos::null;
    using Teuchos::ParameterList;
    using Teuchos::parameterList;
    using Teuchos::RCP;
    using Teuchos::rcp;
    using Teuchos::rcp_dynamic_cast;
    using Teuchos::rcpFromRef;
    using Teuchos::Time;
    using Teuchos::TimeMonitor;
    using Teuchos::Exceptions::InvalidParameter;
    using Teuchos::Exceptions::InvalidParameterName;
    using Teuchos::Exceptions::InvalidParameterType;

    TEUCHOS_TEST_FOR_EXCEPTION(params.is_null(), std::invalid_argument,
                               "Belos::LSQRSolMgr::setParameters: "
                               "the input ParameterList is null.");
    RCP<const ParameterList> defaultParams = getValidParameters ();
    params->validateParametersAndSetDefaults (*defaultParams);

    // At this point, params is a valid parameter list with defaults
    // filled in.  Now we can "commit" it to our instance's parameter
    // list.
    params_ = params;

    // Get the damping (a.k.a. regularization) parameter lambda.
    lambda_ = params->get<MagnitudeType> ("Lambda");

    // Get the maximum number of iterations.
    maxIters_ = params->get<int>("Maximum Iterations");

    // (Re)set the timer label.
    {
        const std::string newLabel = params->get<std::string>("Timer Label");

        // Update parameter in our list and solver timer
        if (newLabel != label_) {
            label_ = newLabel;
        }

#ifdef BELOS_TEUCHOS_TIME_MONITOR
        std::string newSolveLabel = label_ + ": LSQRSolMgr total solve time";
        if (timerSolve_.is_null()) {
            // Ask TimeMonitor for a new timer.
            timerSolve_ = TimeMonitor::getNewCounter (newSolveLabel);
        } else {
            // We've already created a timer, but we may have changed its
            // label.  If we did change its name, then we have to forget
            // about the old timer and create a new one with a different
            // name.  This is because Teuchos::Time doesn't give you a way
            // to change a timer's name, once you've created it.  We assume
            // that if the user changed the timer's label, then the user
            // wants to reset the timer's results.
            const std::string oldSolveLabel = timerSolve_->name ();

            if (oldSolveLabel != newSolveLabel) {
                // Tell TimeMonitor to forget about the old timer.
                // TimeMonitor lets you clear timers by name.
                TimeMonitor::clearCounter (oldSolveLabel);
                timerSolve_ = TimeMonitor::getNewCounter (newSolveLabel);
            }
        }
#endif // BELOS_TEUCHOS_TIME_MONITOR
    }

    // Check for a change in verbosity level
    {
        int newVerbosity = 0;
        // ParameterList gets confused sometimes about enums.  This
        // ensures that no matter how "Verbosity" was stored -- either an
        // an int, or as a Belos::MsgType enum, we will be able to extract
        // it.  If it was stored as some other type, we let the exception
        // through.
        try {
            newVerbosity = params->get<Belos::MsgType> ("Verbosity");
        } catch (Teuchos::Exceptions::InvalidParameterType&) {
            newVerbosity = params->get<int> ("Verbosity");
        }
        if (newVerbosity != verbosity_) {
            verbosity_ = newVerbosity;
        }
    }

    // (Re)set the output style.
    outputStyle_ = params->get<int> ("Output Style");

    // Get the output stream for the output manager.
    //
    // In case the output stream can't be read back in, we default to
    // stdout (std::cout), just to ensure reasonable behavior.
    {
        outputStream_ = params->get<RCP<std::ostream> > ("Output Stream");

        // We assume that a null output stream indicates that the user
        // doesn't want to print anything, so we replace it with a "black
        // hole" stream that prints nothing sent to it.  (We can't use a
        // null output stream, since the output manager always sends
        // things it wants to print to the output stream.)
        if (outputStream_.is_null())
            outputStream_ = rcp (new Teuchos::oblackholestream);
    }

    // Get the frequency of solver output.  (For example, -1 means
    // "never," 1 means "every iteration.")
    outputFreq_ = params->get<int> ("Output Frequency");

    // Create output manager if we need to, using the verbosity level
    // and output stream that we fetched above.  We do this here because
    // instantiating an OrthoManager using OrthoManagerFactory requires
    // a valid OutputManager.
    if (printer_.is_null()) {
        printer_ = rcp (new OutputManager<ScalarType> (verbosity_, outputStream_));
    } else {
        printer_->setVerbosity (verbosity_);
        printer_->setOStream (outputStream_);
    }

    // Check if the orthogonalization changed, or if we need to
    // initialize it.
    typedef OrthoManagerFactory<ScalarType, MV, OP> factory_type;
    factory_type factory;
    bool mustMakeOrtho = false;
    {
        std::string tempOrthoType;
        try {
            tempOrthoType = params_->get<std::string> ("Orthogonalization");
        } catch (InvalidParameterName&) {
            tempOrthoType = orthoType_;
        }
        if (ortho_.is_null() || tempOrthoType != orthoType_) {
            mustMakeOrtho = true;

            // Ensure that the specified orthogonalization type is valid.
            if (! factory.isValidName (tempOrthoType)) {
                std::ostringstream os;
                os << "Belos::LSQRSolMgr: Invalid orthogonalization name \""
                   << tempOrthoType << "\".  The following are valid options "
                   << "for the \"Orthogonalization\" name parameter: ";
                factory.printValidNames (os);
                TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, os.str());
            }
            orthoType_ = tempOrthoType; // The name is valid, so accept it.
            params_->set ("Orthogonalization", orthoType_);
        }
    }

    // Get any parameters for the orthogonalization ("Orthogonalization
    // Parameters").  If not supplied, the orthogonalization manager
    // factory will supply default values.
    //
    // NOTE (mfh 21 Oct 2011) For the sake of backwards compatibility,
    // if params has an "Orthogonalization Constant" parameter and the
    // DGKS orthogonalization manager is to be used, the value of this
    // parameter will override DGKS's "depTol" parameter.
    //
    // Users must supply the orthogonalization manager parameters as a
    // sublist (supplying it as an RCP<ParameterList> would make the
    // resulting parameter list not serializable).
    RCP<ParameterList> orthoParams;
    {   // The nonmember function returns an RCP<ParameterList>,
        // which is what we want here.
        using Teuchos::sublist;
        // Abbreviation to avoid typos.
        const std::string paramName ("Orthogonalization Parameters");

        try {
            orthoParams = sublist (params_, paramName, true);
        } catch (InvalidParameter&) {
            // We didn't get the parameter list from params, so get a
            // default parameter list from the OrthoManagerFactory.
            // Modify params_ so that it has the default parameter list,
            // and set orthoParams to ensure it's a sublist of params_
            // (and not just a copy of one).
            params_->set (paramName, factory.getDefaultParameters (orthoType_));
            orthoParams = sublist (params_, paramName, true);
        }
    }
    TEUCHOS_TEST_FOR_EXCEPTION(orthoParams.is_null(), std::logic_error,
                               "Failed to get orthogonalization parameters.  "
                               "Please report this bug to the Belos developers.");

    // If we need to, instantiate a new MatOrthoManager subclass
    // instance corresponding to the desired orthogonalization method.
    // We've already fetched the orthogonalization method name
    // (orthoType_) and its parameters (orthoParams) above.
    //
    // NOTE (mfh 21 Oct 2011) We only instantiate a new MatOrthoManager
    // subclass if the orthogonalization method name is different than
    // before.  Thus, for some orthogonalization managers, changes to
    // their parameters may not get propagated, if the manager type
    // itself didn't change.  The one exception is the "depTol"
    // (a.k.a. orthoKappa or "Orthogonalization Constant") parameter of
    // DGKS; changes to that _do_ get propagated down to the DGKS
    // instance.
    //
    // The most general way to fix this issue would be to supply each
    // orthogonalization manager class with a setParameterList() method
    // that takes a parameter list input, and changes the parameters as
    // appropriate.  A less efficient but correct way would be simply to
    // reinstantiate the OrthoManager every time, whether or not the
    // orthogonalization method name or parameters have changed.
    if (mustMakeOrtho) {
        // Create orthogonalization manager.  This requires that the
        // OutputManager (printer_) already be initialized.  LSQR
        // currently only orthogonalizes with respect to the Euclidean
        // inner product, so we set the inner product matrix M to null.
        RCP<const OP> M = null;
        ortho_ = factory.makeMatOrthoManager (orthoType_, M, printer_,
                                              label_, orthoParams);
    }
    TEUCHOS_TEST_FOR_EXCEPTION(ortho_.is_null(), std::logic_error,
                               "The MatOrthoManager is not yet initialized, but "
                               "should be by this point.  "
                               "Please report this bug to the Belos developers.");

    // Check which orthogonalization constant to use.  We only need this
    // if orthoType_ == "DGKS" (and we already fetched the orthoType_
    // parameter above).
    if (orthoType_ == "DGKS") {
        if (params->isParameter ("Orthogonalization Constant")) {
            orthoKappa_ = params_->get<MagnitudeType> ("Orthogonalization Constant");

            if (orthoKappa_ > 0 && ! ortho_.is_null()) {
                typedef DGKSOrthoManager<ScalarType,MV,OP> ortho_impl_type;
                rcp_dynamic_cast<ortho_impl_type> (ortho_)->setDepTol (orthoKappa_);
            }
        }
    }

    // Check for condition number limit, number of consecutive passed
    // iterations, relative RHS error, and relative matrix error.
    // Create the LSQR convergence test if necessary.
    {
        condMax_ = params->get<MagnitudeType> ("Condition Limit");
        termIterMax_ = params->get<int>("Term Iter Max");
        relRhsErr_ = params->get<MagnitudeType> ("Rel RHS Err");
        relMatErr_ = params->get<MagnitudeType> ("Rel Mat Err");

        // Create the LSQR convergence test if it doesn't exist yet.
        // Otherwise, update its parameters.
        if (convTest_.is_null()) {
            convTest_ =
                rcp (new LSQRStatusTest<ScalarType,MV,OP> (condMax_, termIterMax_,
                        relRhsErr_, relMatErr_));
        } else {
            convTest_->setCondLim (condMax_);
            convTest_->setTermIterMax (termIterMax_);
            convTest_->setRelRhsErr (relRhsErr_);
            convTest_->setRelMatErr (relMatErr_);
        }
    }

    // Create the status test for maximum number of iterations if
    // necessary.  Otherwise, update it with the new maximum iteration
    // count.
    if (maxIterTest_.is_null()) {
        maxIterTest_ = rcp (new StatusTestMaxIters<ScalarType,MV,OP> (maxIters_));
    } else {
        maxIterTest_->setMaxIters (maxIters_);
    }

    // The stopping criterion is an OR combination of the test for
    // maximum number of iterations, and the LSQR convergence test.
    // ("OR combination" means that both tests will always be evaluated,
    // as opposed to a SEQ combination.)
    typedef StatusTestCombo<ScalarType,MV,OP>  StatusTestCombo_t;
    // If sTest_ is not null, then maxIterTest_ and convTest_ were
    // already constructed on entry to this routine, and sTest_ has
    // their pointers.  Thus, maxIterTest_ and convTest_ have gotten any
    // parameter changes, so we don't need to do anything to sTest_.
    if (sTest_.is_null()) {
        sTest_ = rcp (new StatusTestCombo_t (StatusTestCombo_t::OR,
                                             maxIterTest_,
                                             convTest_));
    }

    if (outputTest_.is_null()) {
        // Create the status test output class.
        // This class manages and formats the output from the status test.
        StatusTestOutputFactory<ScalarType,MV,OP> stoFactory (outputStyle_);
        outputTest_ = stoFactory.create (printer_, sTest_, outputFreq_,
                                         Passed + Failed + Undefined);
        // Set the solver string for the output test.
        const std::string solverDesc = " LSQR ";
        outputTest_->setSolverDesc (solverDesc);
    } else {
        // FIXME (mfh 18 Sep 2011) How do we change the output style of
        // outputTest_, without destroying and recreating it?
        outputTest_->setOutputManager (printer_);
        outputTest_->setChild (sTest_);
        outputTest_->setOutputFrequency (outputFreq_);
        // Since outputTest_ can only be created here, I'm assuming that
        // the fourth constructor argument ("printStates") was set
        // correctly on constrution; I don't need to reset it (and I can't
        // set it anyway, given StatusTestOutput's interface).
    }

    // Inform the solver manager that the current parameters were set.
    isSet_ = true;
}
예제 #2
0
  void
  MinresSolMgr<ScalarType, MV, OP>::
  setParameters (const Teuchos::RCP<Teuchos::ParameterList>& params)
  {
    using Teuchos::ParameterList;
    using Teuchos::parameterList;
    using Teuchos::RCP;
    using Teuchos::rcp;
    using Teuchos::rcpFromRef;
    using Teuchos::null;
    using Teuchos::is_null;
    using std::string;
    using std::ostream;
    using std::endl;

    if (params_.is_null()) {
      params_ = parameterList (*getValidParameters());
    }
    RCP<ParameterList> pl = params;
    pl->validateParametersAndSetDefaults (*params_);

    //
    // Read parameters from the parameter list.  We have already
    // populated it with defaults.
    //
    blockSize_ = pl->get<int> ("Block Size");
    verbosity_ = pl->get<int> ("Verbosity");
    outputStyle_ = pl->get<int> ("Output Style");
    outputFreq_ = pl->get<int>("Output Frequency");
    outputStream_ = pl->get<RCP<std::ostream> > ("Output Stream");
    convtol_ = pl->get<MagnitudeType> ("Convergence Tolerance");
    maxIters_ = pl->get<int> ("Maximum Iterations");
    //
    // All done reading parameters from the parameter list.
    // Now we know it's valid and we can store it.
    //
    params_ = pl;

    // Change the timer label, and create the timer if necessary.
    const string newLabel = pl->get<string> ("Timer Label");
    {
      if (newLabel != label_ || timerSolve_.is_null()) {
	label_ = newLabel;
#ifdef BELOS_TEUCHOS_TIME_MONITOR
	const string solveLabel = label_ + ": MinresSolMgr total solve time";
	// Unregister the old timer before creating a new one.
	if (! timerSolve_.is_null()) {
	  Teuchos::TimeMonitor::clearCounter (label_);
	  timerSolve_ = Teuchos::null;
	}
	timerSolve_ = Teuchos::TimeMonitor::getNewCounter (solveLabel);
#endif // BELOS_TEUCHOS_TIME_MONITOR
      }
    }

    // Create output manager, if necessary; otherwise, set its parameters.
    bool recreatedPrinter = false;
    if (printer_.is_null()) {
      printer_ = rcp (new OutputManager<ScalarType> (verbosity_, outputStream_));
      recreatedPrinter = true;
    } else {
      // Set the output stream's verbosity level.
      printer_->setVerbosity (verbosity_);
      // Tell the output manager about the new output stream.
      printer_->setOStream (outputStream_);
    }

    //
    // Set up the convergence tests
    //
    typedef StatusTestGenResNorm<ScalarType, MV, OP> res_norm_type;
    typedef StatusTestCombo<ScalarType, MV, OP> combo_type;

    // Do we need to allocate at least one of the implicit or explicit
    // residual norm convergence tests?
    const bool allocatedConvergenceTests =
      impConvTest_.is_null() || expConvTest_.is_null();

    // Allocate or set the tolerance of the implicit residual norm
    // convergence test.
    if (impConvTest_.is_null()) {
      impConvTest_ = rcp (new res_norm_type (convtol_));
      impConvTest_->defineResForm (res_norm_type::Implicit, TwoNorm);
      // TODO (mfh 03 Nov 2011) Allow users to define the type of
      // scaling (or a custom scaling factor).
      impConvTest_->defineScaleForm (NormOfInitRes, TwoNorm);
    } else {
      impConvTest_->setTolerance (convtol_);
    }

    // Allocate or set the tolerance of the explicit residual norm
    // convergence test.
    if (expConvTest_.is_null()) {
      expConvTest_ = rcp (new res_norm_type (convtol_));
      expConvTest_->defineResForm (res_norm_type::Explicit, TwoNorm);
      // TODO (mfh 03 Nov 2011) Allow users to define the type of
      // scaling (or a custom scaling factor).
      expConvTest_->defineScaleForm (NormOfInitRes, TwoNorm);
    } else {
      expConvTest_->setTolerance (convtol_);
    }

    // Whether we need to recreate the full status test.  We only need
    // to do that if at least one of convTest_ or maxIterTest_ had to
    // be reallocated.
    bool needToRecreateFullStatusTest = sTest_.is_null();

    // Residual status test is a combo of the implicit and explicit
    // convergence tests.
    if (convTest_.is_null() || allocatedConvergenceTests) {
      convTest_ = rcp (new combo_type (combo_type::SEQ, impConvTest_, expConvTest_));
      needToRecreateFullStatusTest = true;
    }

    // Maximum number of iterations status test.  It tells the solver to
    // stop iteration, if the maximum number of iterations has been
    // exceeded.  Initialize it if we haven't yet done so, otherwise
    // tell it the new maximum number of iterations.
    if (maxIterTest_.is_null()) {
      maxIterTest_ = rcp (new StatusTestMaxIters<ScalarType,MV,OP> (maxIters_));
      needToRecreateFullStatusTest = true;
    } else {
      maxIterTest_->setMaxIters (maxIters_);
    }

    // Create the full status test if we need to.
    //
    // The full status test: the maximum number of iterations have
    // been reached, OR the residual has converged.
    //
    // "If we need to" means either that the status test was never
    // created before, or that its two component tests had to be
    // reallocated.
    if (needToRecreateFullStatusTest) {
      sTest_ = rcp (new combo_type (combo_type::OR, maxIterTest_, convTest_));
    }

    // If necessary, create the status test output class.  This class
    // manages and formats the output from the status test.  We have
    // to recreate the output test if we had to (re)allocate either
    // printer_ or sTest_.
    if (outputTest_.is_null() || needToRecreateFullStatusTest || recreatedPrinter) {
      StatusTestOutputFactory<ScalarType,MV,OP> stoFactory (outputStyle_);
      outputTest_ = stoFactory.create (printer_, sTest_, outputFreq_,
				       Passed+Failed+Undefined);
    } else {
      outputTest_->setOutputFrequency (outputFreq_);
    }
    // Set the solver string for the output test.
    // StatusTestOutputFactory has no constructor argument for this.
    outputTest_->setSolverDesc (std::string (" MINRES "));

    // Inform the solver manager that the current parameters were set.
    parametersSet_ = true;

    if (verbosity_ & Debug) {
      using std::endl;

      std::ostream& dbg = printer_->stream (Debug);
      dbg << "MINRES parameters:" << endl << params_ << endl;
    }
  }