CollOfScalar EquelleRuntimeCPU::solveForUpdate(const CollOfScalar& residual) const { Eigen::SparseMatrix<double, Eigen::RowMajor> matr = residual.derivative()[0]; CollOfScalar::V du = CollOfScalar::V::Zero(residual.size()); Opm::time::StopWatch clock; clock.start(); // solve(n, # nonzero values ("val"), ptr to col indices // ("col_ind"), ptr to row locations in val array ("row_ind") // (these two may be swapped, not sure about the naming convention // here...), array of actual values ("val") (I guess... '*sa'...), // rhs, solution) Opm::LinearSolverInterface::LinearSolverReport rep = linsolver_.solve(matr.rows(), matr.nonZeros(), matr.outerIndexPtr(), matr.innerIndexPtr(), matr.valuePtr(), residual.value().data(), du.data()); if (verbose_ > 2) { std::cout << " solveForUpdate: Linear solver took: " << clock.secsSinceLast() << " seconds." << std::endl; } if (!rep.converged) { OPM_THROW(std::runtime_error, "Linear solver convergence failure."); } return du; }
CollOfScalar EquelleRuntimeCPU::singlePrimaryVariable(const CollOfScalar& initial_values) { std::vector<int> block_pattern; block_pattern.push_back(initial_values.size()); // Syntax below is: CollOfScalar::variable(block index, initialized from, block structure) return CollOfScalar::variable(0, initial_values.value(), block_pattern); }
void EquelleRuntimeCPU::output(const String& tag, const CollOfScalar& vals) { if (output_to_file_) { int count = -1; auto it = outputcount_.find(tag); if (it == outputcount_.end()) { count = 0; outputcount_[tag] = 1; // should contain the count to be used next time for same tag. } else { count = outputcount_[tag]; ++outputcount_[tag]; } std::ostringstream fname; fname << tag << "-" << std::setw(5) << std::setfill('0') << count << ".output"; std::ofstream file(fname.str().c_str()); if (!file) { OPM_THROW(std::runtime_error, "Failed to open " << fname.str()); } file.precision(16); std::copy(vals.value().data(), vals.value().data() + vals.size(), std::ostream_iterator<double>(file, "\n")); } else { std::cout << tag << " =\n"; for (int i = 0; i < vals.size(); ++i) { std::cout << std::setw(15) << std::left << ( vals.value()[i] ) << " "; } std::cout << std::endl; } }
CollOfScalar EquelleRuntimeCUDA::operatorOn(const CollOfScalar& data_in, const CollOfIndices<codim>& from_set, const CollOfIndices<codim>& to_set) { if ( data_in.size() != from_set.size()) { OPM_THROW(std::logic_error, "data_in (size " << data_in.size() << ") and from_set (size " << from_set.size() << ") have to be of the same size in On function for CollOfScalar."); } //if ( to_set.size() > from_set.size() ) { // OPM_THROW(std::runtime_error, "To_set (size " << to_set.size() << ") has to be a subset of from_set (size " << from_set.size() << ")"); //} return dev_grid_.operatorOn(data_in, from_set, to_set); }
CollOfScalar EquelleRuntimeCUDA::operatorExtend(const CollOfScalar& data_in, const CollOfIndices<codim>& from_set, const CollOfIndices<codim>& to_set) const { if (data_in.size() != from_set.size() ) { OPM_THROW(std::runtime_error, "data_in (size " << data_in.size() << ") and from_set (size " << from_set.size() << ") have to be of the same size in Extend function."); } if (from_set.size() > to_set.size() ) { OPM_THROW(std::runtime_error, "From_set (size " << from_set.size() << ") has to be a subset of to_set (size " << to_set.size() << ")"); } return dev_grid_.operatorExtend(data_in, from_set, to_set); }
/// This function is not provided by AutoDiffBlock, so we must add it here. inline CollOfScalar sqrt(const CollOfScalar& x) { // d(sqrt(x))/dy = 1/(2*sqrt(x)) * dx/dy const auto& xjac = x.derivative(); if (xjac.empty()) { return CollOfScalar(sqrt(x.value())); } const int num_blocks = xjac.size(); std::vector<CollOfScalar::M> jac(num_blocks); const auto sqrt_x = sqrt(x.value()); const CollOfScalar::M one_over_two_sqrt_x((0.5/sqrt_x).matrix().asDiagonal()); for (int block = 0; block < num_blocks; ++block) { jac[block] = one_over_two_sqrt_x * xjac[block]; } return CollOfScalar::ADB::function(sqrt_x, jac); }
CollOfScalar EquelleRuntimeCPU::divergence(const CollOfScalar& face_fluxes) const { if (face_fluxes.size() == ops_.internal_faces.size()) { // This is actually a hack, the compiler should know to emit interiorDivergence() // eventually, but as a temporary measure we do this. return interiorDivergence(face_fluxes); } return ops_.fulldiv * face_fluxes;//.matrix(); }
int compare(CollOfScalar scal, double sol[], int sol_size, std::string test) { // Test size: if ( scal.size() != sol_size ) { std::cout << "Error in valsOnGrid.cpp - testing " << test << "\n"; std::cout << "\tThe collection is of wrong size!\n"; std::cout << "\tSize is " << scal.size() << " but should be " << sol_size << "\n"; return 1; } // Testing indices std::vector<double> host = scal.copyToHost(); std::cout << "CollOfScalar " << test << " is the following:\n"; bool correct = true; for (int i = 0; i < host.size(); ++i) { std::cout << host[i] << " "; if (i < sol_size) { //if (host[i] != sol[i]) { if ( fabs(host[i] - sol[i]) > 1000*std::numeric_limits<double>::epsilon() ) { std::cout << "(<- " << sol[i] << ") "; correct = false; } } } if (correct) { std::cout << "\n\tThis is correct\n"; } else { std::cout << "\n\tThis is wrong\n"; std::cout << "Error in valsOnGrid.cpp - testing " << test << "\n"; std::cout << "\tThe indices in the collection is wrong\n"; return 1; } return 0; }
/// This operator is not provided by AutoDiffBlock, so we must add it here. inline CollOfScalar operator/(const Scalar& s, const CollOfScalar& x) { return CollOfScalar::V::Constant(x.size(), s) / x; }
/// This operator is not provided by AutoDiffBlock, so we must add it here. inline CollOfScalar operator/(const CollOfScalar& x, const Scalar& s) { return x / CollOfScalar::V::Constant(x.size(), s); }
Scalar EquelleRuntimeCPU::maxReduce(const CollOfScalar& x) const { return x.value().maxCoeff(); }
/// This operator is not provided by AutoDiffBlock, so we must add it here. inline CollOfScalar operator-(const CollOfScalar& x) { return CollOfScalar::V::Zero(x.size()) - x; }
/// This operator is not provided by AutoDiffBlock, so we must add it here. inline CollOfBool operator==(const CollOfScalar& x, const Scalar& s) { return x.value() == s; }
/// This operator is not provided by AutoDiffBlock, so we must add it here. inline CollOfBool operator==(const CollOfScalar& x, const CollOfScalar& y) { return x.value() == y.value(); }
/// This operator is not provided by AutoDiffBlock, so we must add it here. inline CollOfBool operator==(const Scalar& s, const CollOfScalar& x) { return s == x.value(); }
CollOfScalar EquelleRuntimeCUDA::newtonSolve(const ResidualFunctor& rescomp, const CollOfScalar& u_initialguess) { Opm::time::StopWatch clock; clock.start(); // Set up Newton loop. // Define the primary variable CollOfScalar u = CollOfScalar(u_initialguess, true); if (verbose_ > 2) { output("Initial u", u); output(" newtonSolve: norm (initial u)", twoNorm(u)); } CollOfScalar residual = rescomp(u); if (verbose_ > 2) { output("Initial residual", residual); output(" newtonSolve: norm (initial residual)", twoNorm(residual)); } int iter = 0; // Debugging output not specified in Equelle. if (verbose_ > 1) { std::cout << " newtonSolve: iter = " << iter << " (max = " << max_iter_ << "), norm(residual) = " << twoNorm(residual) << " (tol = " << abs_res_tol_ << ")" << std::endl; } CollOfScalar du; // Execute newton loop until residual is small or we have used too many iterations. while ( (twoNorm(residual) > abs_res_tol_) && (iter < max_iter_) ) { if ( solver_.getSolver() == CPU ) { du = serialSolveForUpdate(residual); } else { // Solve linear equations for du, apply update. du = solver_.solve(residual.derivative(), residual.value(), verbose_); } // du is a constant, hence, u is still a primary variable with an identity // matrix as its derivative. u = u - du; // Recompute residual. residual = rescomp(u); if (verbose_ > 2) { // Debugging output not specified in Equelle. output("u", u); output(" newtonSolve: norm(u)", twoNorm(u)); output("residual", residual); output(" newtonSolve: norm(residual)", twoNorm(residual)); } ++iter; // Debugging output not specified in Equelle. if (verbose_ > 1) { std::cout << " newtonSolve: iter = " << iter << " (max = " << max_iter_ << "), norm(residual) = " << twoNorm(residual) << " (tol = " << abs_res_tol_ << ")" << std::endl; } } if (verbose_ > 0) { if (twoNorm(residual) > abs_res_tol_) { std::cout << "Newton solver failed to converge in " << max_iter_ << " iterations" << std::endl; } else { std::cout << "Newton solver converged in " << iter << " iterations" << std::endl; } } if (verbose_ > 1) { std::cout << "Newton solver took: " << clock.secsSinceLast() << " seconds." << std::endl; } return CollOfScalar(u.value()); }
Scalar EquelleRuntimeCPU::sumReduce(const CollOfScalar& x) const { return x.value().sum(); }
Scalar EquelleRuntimeCPU::prodReduce(const CollOfScalar& x) const { return x.value().prod(); }
double EquelleRuntimeCPU::twoNorm(const CollOfScalar& vals) const { return vals.value().matrix().norm(); }