// tasystem.cpp // // last-edit-by: J.A. de Jong // // Description: // ////////////////////////////////////////////////////////////////////// #include "segment.h" #include "tasystem.h" #include "triplets.h" #include "jacobian.h" #include "tasmet_utils.h" #include "tasmet_assert.h" #include "tasmet_exception.h" #include "tasmet_constants.h" #include "duct.h" #include "ductbc.h" TaSystem::TaSystem(const pb::System& sys): GlobalConf(sys.nf(),sys.freq()) { TRACE(14,"TaSystem::TaSystem()"); if(sys.systemtype() != pb::TaSystem) { throw TaSMETError("Invalid system type for TaSystem"); } // Checking parameters T0 and p0 also happens in newGas method _gas = std::unique_ptr(Gas::newGas(sys.gastype(),sys.t0(),sys.p0())); if(!_gas) throw TaSMETBadAlloc(); // Create all ducts for(const auto& d : sys.ducts()) { // d.first: id // d.second: duct description try { _segs[d.first] = new Duct(d.first,d.second); if(!_segs[d.first]) throw TaSMETBadAlloc(); } catch(TaSMETError e) { // Cleanup the already successfully created Ducts and rethrow cleanup(); throw e; } } // Create all ductbcs for(const auto& d : sys.ductbcs()) { // d.first: id // d.second: duct description try { _segs[d.first] = DuctBc::newDuctBc(d.first, *this, d.second); if(!_segs[d.first]) throw TaSMETBadAlloc(); } catch(TaSMETError e) { // Cleanup the already successfully created Ducts and rethrow cleanup(); throw e; } } // Create the initial solution from the segments and store it // here. Please be careful not to call any virtual functions! vus ndofs = getNDofs(); vus dofend = arma::cumsum(ndofs); us total_dofs = arma::sum(ndofs); vd solution = vd(total_dofs); us i=0; const Segment* seg; for(auto& seg_: _segs) { seg = seg_.second; if(ndofs(i)>0) { if(i==0) { solution.subvec(0,ndofs(0)-1) = seg->initialSolution(*this); } else { solution.subvec(dofend(i-1),dofend(i)-1) = seg->initialSolution(*this); } i++; } } // TODO: work directly on the final solution array _solution = solution; // Copy solution vector, if valid // const auto& sol = sys.solution(); // us size = sol.size(), i=0; // if(size>0) { // _solution = vd(size); // for(auto& val: sol) { // _solution(i) = val; // i++; // } // } } TaSystem::TaSystem(const TaSystem& o): GlobalConf(o), // Share a ptr to the Global conf _gas(o._gas->copy()), _solution(o._solution) { TRACE(25,"TaSystem::TaSystem(TaSystem&) copy"); // Take over the pointers to the segments _segs = o._segs; for(auto& seg: _segs){ seg.second = seg.second->copy(); if(!seg.second) throw TaSMETBadAlloc(); } } int TaSystem::getArbitrateMassEq(const vus& neqs) const { // Tells the TaSystem which Dof should be overwritten with the // mass arbitration equation. The special value of -1 means, that // mass is not arbitrated. This can be the case if for example a // pressure boundary condition is present. int arbitrateMassEq=-1; bool masseq_found = false; us total_neqs = 0, i=0; // Iterate over all segments to find a single one segment Dof that is // willing to arbitrate the mass in the system. This can, of // course, be only be one segment. int local_mass_eq = -1; const Segment* seg; for(auto& seg_: _segs) { seg = seg_.second; if(masseq_found && (local_mass_eq = seg->arbitrateMassEq())) { throw TaSMETError("Error: only one Segment is allowed to" " arbitrate the system mass"); } else if(local_mass_eq != -1){ arbitrateMassEq = total_neqs+local_mass_eq; masseq_found = true; } total_neqs += neqs(i); i++; } return arbitrateMassEq; } vd TaSystem::residual() const { TRACE(15,"TaSystem::residual()"); vus neqs = getNEqs(); us total_neqs = arma::sum(neqs); if(total_neqs>constants::maxndofs) { stringstream error; error << "Too many DOFS required. Problem too large. Number of equations computed: "; error << total_neqs; throw TaSMETError(error); } // This vector of indices stores the last equation number + 1 for // each equation set in a Segment vus eqsend = arma::cumsum(neqs); int arbitrateMassEq = getArbitrateMassEq(neqs); // This is the mass in the sytem. Only counted when there is an // equation present which arbitrates the mass in the system d mass=0; VARTRACE(25,total_neqs); VARTRACE(25,eqsend); vd residual(total_neqs); #ifdef TASMET_DEBUG residual = arma::datum::nan*ones(total_neqs); #endif us i=0; const Segment* seg; for(auto seg_: _segs) { seg = seg_.second; if(i==0) { // Put the residual of the segment in the over-all residual seg->residual(*this,residual.subvec(0,eqsend(0)-1)); } else { seg->residual(*this,residual.subvec(eqsend(i-1),eqsend(i)-1)); } // Count the mass, add it if(arbitrateMassEq!=-1) { mass += seg->getMass(*this); } i++; } TRACE(15,"Obtained residual from all Segments"); #ifdef TASMET_DEBUG assert(arbitrateMassEq< (int) total_neqs); #endif // TASMET_DEBUG // Exchange equation if we need to arbitrate mass if(arbitrateMassEq!=-1) { residual(arbitrateMassEq)=mass - _mass; } return residual; } vd TaSystem::getSolution() const { return _solution; } const arma::subview_col TaSystem::getSolution(const us seg_id) const { vus ndofs = getNDofs(); vus dofsend = arma::cumsum(ndofs); VARTRACE(15,dofsend); VARTRACE(15,seg_id); if(seg_id == 0) { VARTRACE(15,_solution.size()); return _solution.subvec(0,dofsend(0)-1); } else { return _solution.subvec(dofsend(seg_id-1),dofsend(seg_id)-1); } } vus TaSystem::getNDofs() const { TRACE(0,"TaSystem::getNDofs()"); vus Ndofs(_segs.size()); us i=0; for (auto seg : _segs) { Ndofs(i)=seg.second->getNDofs(*this); i++; } return Ndofs; } vus TaSystem::getNEqs() const { TRACE(15,"TaSystem::getNEqs()"); vus Neqs(_segs.size()); us i=0; for (auto seg :_segs) { Neqs(i)=seg.second->getNEqs(*this); VARTRACE(15,Neqs(i)); i++; } return Neqs; } void TaSystem::show(us detailnr){ TRACE(25,"TaSystem::show()"); cout << "########################## Showing TaSystem...\n"; cout << "Showing Global configuration...\n"; GlobalConf::show(); if(detailnr>0){ for(auto seg:_segs){ cout << "Showing segment with ID " << seg.first << "\n"; seg.second->show(*this,detailnr); } } // detailnr>0 } TripletList TaSystem::jacTriplets() const { TRACE(14,"TaSystem::jacobian()"); vus ndofs=getNDofs(); vus neqs=getNEqs(); us total_ndofs = arma::sum(ndofs); us total_neqs = arma::sum(neqs); us i=0,dofnr=0,eqnr=0; Jacobian j(total_ndofs); int arbitrateMassEq = getArbitrateMassEq(neqs); vd dmtotdx; if(arbitrateMassEq > -1) dmtotdx = vd(total_ndofs); const Segment* seg; for(auto& seg_ :_segs) { seg = seg_.second; seg->jac(*this,j,dofnr,eqnr); if(arbitrateMassEq > -1) { seg->dmtotdx(*this,dmtotdx,dofnr); } eqnr += neqs(i); dofnr += ndofs(i); i++; } if(dofnr!=eqnr){ throw TaSMETError("System of equations is over/underdetermined"); } // Convert to tripletlist TripletList jac=j; assert(arbitrateMassEq< (int) total_neqs); // Exchange equation if we need to arbitrate mass if(arbitrateMassEq!=-1) { // Replace this equation with global mass conservation jac.zeroOutRow(arbitrateMassEq); us dmtotdxsize=dmtotdx.size(); for(us k=0;kresetHarmonics(); // } // } dmat TaSystem::showJac(){ TRACE(15,"TaSystem::showJac()"); return dmat(jacobian()); } TaSystem::~TaSystem() { TRACE(25,"~TaSystem()"); cleanup(); } void TaSystem::cleanup() { purge(_segs); } //////////////////////////////////////////////////////////////////////