// Header file for this class #include "ImplicitSolveOperator.h" // Other ATC includes #include "ATC_Coupling.h" #include "FE_Engine.h" #include "PhysicsModel.h" #include "PrescribedDataManager.h" using std::set; using std::vector; namespace ATC { // -------------------------------------------------------------------- // -------------------------------------------------------------------- // ImplicitSolveOperator // -------------------------------------------------------------------- // -------------------------------------------------------------------- ImplicitSolveOperator:: ImplicitSolveOperator(double alpha, double dt) : n_(0), dof_(0), dt_(dt), alpha_(alpha), epsilon0_(1.0e-8) { // Nothing else to do here } // -------------------------------------------------------------------- // operator * // -------------------------------------------------------------------- DENS_VEC ImplicitSolveOperator::operator * (const DENS_VEC & x) const { // This method uses a matrix-free approach to approximate the // multiplication by matrix A in the matrix equation Ax=b, where the // matrix equation results from an implicit treatment of the // fast field. In brief, if the ODE for the fast field can be written: // // dx/dt = R(x) // // A generalized discretization can be written: // // 1/dt * (x^n+1 - x^n) = alpha * R(x^n+1) + (1-alpha) * R(x^n) // // Taylor expanding the R(x^n+1) term and rearranging gives the // equation to be solved for dx at each timestep: // // [1 - dt * alpha * dR/dx] * dx = dt * R(x^n) // // The operator defined in this method computes the left-hand side, // given a vector dx. It uses a finite difference, matrix-free // approximation of dR/dx * dx, giving: // // [1 - dt * alpha * dR/dx] * dx = dt * R(x^n) // ~= dx - dt*alpha/epsilon * ( R(x^n + epsilon*dx) - R(x^n) ) // // Compute epsilon double epsilon = (x.norm()>0.0) ? epsilon0_*x0_.norm()/x.norm():epsilon0_; // Compute incremented vector x^n+1 = x^n + epsilon*dx x_ = x0_ + epsilon * x; // Evaluate R(x) this->R(x_,R_); // Compute full left hand side and return it DENS_VEC Ax = x - dt_ * alpha_ / epsilon * (R_ - R0_); return Ax; } // -------------------------------------------------------------------- // rhs of Ax = r // -------------------------------------------------------------------- DENS_VEC ImplicitSolveOperator::r() const { return dt_ * R0_; // dt * R(T^n) } // -------------------------------------------------------------------- // preconditioner // -------------------------------------------------------------------- DIAG_MAT ImplicitSolveOperator::preconditioner() const { DENS_VEC diag(n_); diag = 1.0; DIAG_MAT preconditioner(diag); return preconditioner; } // -------------------------------------------------------------------- // -------------------------------------------------------------------- // FieldImplicitSolveOperator // -------------------------------------------------------------------- // -------------------------------------------------------------------- FieldImplicitSolveOperator:: FieldImplicitSolveOperator(ATC_Coupling * atc, FIELDS & fields, const FieldName fieldName, const Array2D< bool > & rhsMask, const PhysicsModel * physicsModel, double simTime, double dt, double alpha) : ImplicitSolveOperator(alpha, dt), fieldName_(fieldName), atc_(atc), physicsModel_(physicsModel), fields0_(fields), // ref to fields fields_ (fields), // copy of fields rhsMask_(rhsMask), time_(simTime) { const DENS_MAT & f = fields0_[fieldName_].quantity(); dof_ = f.nCols(); if (dof_ > 1) throw ATC_Error("Implicit solver operator can only handle scalar fields"); // create all to free map int nNodes = f.nRows(); set fixedNodes_ = atc_->prescribed_data_manager()->fixed_nodes(fieldName_); n_ = nNodes; vector tag(nNodes); set::const_iterator it; int i = 0; for (i = 0; i < nNodes; ++i) { tag[i] = true; } for (it=fixedNodes_.begin();it!=fixedNodes_.end();++it) {tag[*it]=false;} int m = 0; for (i = 0; i < nNodes; ++i) { if (tag[i]) freeNodes_[i]= m++; } //std::cout << " nodes " << n_ << " " << nNodes << "\n"; // Save current field x0_.reset(n_); to_free(f,x0_); x_ = x0_; // initialize // righthand side/forcing vector rhsMask_.reset(NUM_FIELDS,NUM_FLUX); rhsMask_ = false; for (int i = 0; i < rhsMask.nCols(); i++) { rhsMask_(fieldName_,i) = rhsMask(fieldName_,i); } //std::cout << print_mask(rhsMask_) << "\n"; massMask_.reset(1); massMask_(0) = fieldName_; rhs_[fieldName_].reset(nNodes,dof_); // Compute the RHS vector R(T^n) R0_.reset(n_); R_ .reset(n_); R(x0_, R0_); } void FieldImplicitSolveOperator::to_all(const VECTOR &x, MATRIX &f) const { f.reset(x.nRows(),1); for (int i = 0; i < x.nRows(); ++i) { f(i,0) = x(i); } } void FieldImplicitSolveOperator::to_free(const MATRIX &r, VECTOR &v) const { v.reset(r.nRows()); for (int i = 0; i < r.nRows(); ++i) { v(i) = r(i,0); } } void FieldImplicitSolveOperator::R(const DENS_VEC &x, DENS_VEC &v ) const { DENS_MAT & f = fields_[fieldName_].set_quantity(); atc_->prescribed_data_manager()->set_fixed_field(time_, fieldName_, f); to_all(x,f); atc_->compute_rhs_vector(rhsMask_,fields_,rhs_,FULL_DOMAIN,physicsModel_); DENS_MAT & r = rhs_[fieldName_].set_quantity(); atc_->prescribed_data_manager()->set_fixed_dfield(time_, fieldName_, r); atc_->apply_inverse_mass_matrix(r,fieldName_); to_free(r,v); #if 0 int n = 6; //std::cout << "# x "; for (int i = 0; i < n_; ++i) std::cout << x(i) << " "; std::cout << "\n"; //std::cout << "# f "; for (int i = 0; i < n; ++i) std::cout << f(i,0) << " "; std::cout << "\n"; std::cout << "# r "; for (int i = 0; i < n; ++i) std::cout << r(i,0) << " "; std::cout << "\n"; //std::cout << "# v "; for (int i = 0; i < n; ++i) std::cout << v(i) << " "; std::cout << "\n"; #endif } void FieldImplicitSolveOperator::solution(const DENS_MAT & dx, DENS_MAT &f) const { DENS_MAT & df = fields_[fieldName_].set_quantity(); to_all(column(dx,0),df); atc_->prescribed_data_manager()->set_fixed_dfield(time_, fieldName_, df); f += df; } void FieldImplicitSolveOperator::rhs(const DENS_MAT & r, DENS_MAT &rhs) const { to_all(column(r,0),rhs); } } // namespace ATC