Working! New way of obtaining Jacobian succesfully implemented. Newton-Raphson solver working

This commit is contained in:
Anne de Jong 2017-01-26 15:03:34 +01:00
parent 328905b461
commit c81e17cecc
20 changed files with 416 additions and 399 deletions

View File

@ -65,9 +65,8 @@ add_library(tasmet_src
# sys/enginesystem.cpp
sys/globalconf.cpp
sys/tasmet_variable.cpp
sys/jaccol.cpp
sys/jacobian.cpp
sys/jacrow.cpp
sys/tasystem.cpp
sys/triplets.cpp
)

View File

@ -60,12 +60,11 @@ Duct::~Duct() {
// delete eq;
// }
}
void Duct::residualJac(arma::subview_col<d> && residual) const {
void Duct::residualJac(SegPositionMapper& residual,
SegJacRows& jacrows) const {
TRACE(15,"Duct::residual()");
TRACE(15,"Duct::residualJac()");
const arma::subview_col<d> sol = sys.getSolution(_id);
vd rho,u,T,p,Ts; // Solution at this gp
vd rhop,up,Tp,pp,Tsp; // Solution at next gp
@ -78,28 +77,26 @@ void Duct::residualJac(arma::subview_col<d> && residual) const {
us number_eqs = 4;
number_eqs += (has_solideq) ? 1 : 0;
// rho,u,T,p
// Ts maybe
us nvars_per_gp = (_ductpb.stempmodel()
== pb::HeatBalance ? 5 : 4);
VARTRACE(15,number_eqs);
us Ns = sys.Ns();
us eq_offset = 0; // Equation offset for current gp
us res_offset = 0; // Residual offset for current gp
us res_offsetp = 0; // Residual offset for next gp
us gp_jump = number_eqs * Ns; // The jump per gp
rhop = getvart(constants::rho,0);
up = getvart(constants::u,0);
Tp = getvart(constants::T,0);
pp = getvart(constants::p,0);
pp = getvart(constants::p,0);
const Gas& gas = sys.gas();
us i=0;
for(us gp=0;gp<ngp()-1;gp++) {
eq_offset = gp*Ns*number_eqs;
res_offset = eq_offset;
res_offsetp = res_offset + gp_jump;
d dx = x(gp+1)-x(gp);
// Update the current gp solution
@ -112,8 +109,35 @@ void Duct::residualJac(arma::subview_col<d> && residual) const {
pp = getvart(constants::p,gp+1);
cont = ((rhop%up)-(rho%u))/dx;
*residual.at(i) = cont;
jacrows.at(i)[{_id,gp*nvars_per_gp+constants::u}] =
-diagmat(rho)/dx;
jacrows.at(i)[{_id,gp*nvars_per_gp+constants::rho}] =
-diagmat(u)/dx;
jacrows.at(i)[{_id,(gp+1)*nvars_per_gp+constants::rho}] =
diagmat(up)/dx;
jacrows.at(i)[{_id,(gp+1)*nvars_per_gp+constants::u}] =
diagmat(rhop)/dx;
TRACE(15,"SFSG");
i++;
mom = (rhop%up%up - rho%u%u + pp - p)/dx;
jacrows.at(i)[{_id,gp*nvars_per_gp+constants::u}] =
-diagmat(rho%u)/dx;
jacrows.at(i)[{_id,gp*nvars_per_gp+constants::rho}] =
-diagmat(u%u)/dx;
jacrows.at(i)[{_id,(gp+1)*nvars_per_gp+constants::rho}] =
diagmat(u%u)/dx;
jacrows.at(i)[{_id,(gp+1)*nvars_per_gp+constants::u}] =
diagmat(up%rhop)/dx;
jacrows.at(i)[{_id,(gp)*nvars_per_gp+constants::p}] =
-eye(Ns,Ns)/dx;
jacrows.at(i)[{_id,(gp+1)*nvars_per_gp+constants::p}] =
eye(Ns,Ns)/dx;
*residual.at(i) = mom;
TRACE(15,"SFSG");
i++;
switch (_ductpb.htmodel()) {
case pb::Isentropic: {
@ -125,33 +149,53 @@ void Duct::residualJac(arma::subview_col<d> && residual) const {
en = p/p0 - pow(rho/rho0,gamma0);
*residual.at(i) = en;
jacrows.at(i)[{_id,gp*nvars_per_gp+constants::p}] =
eye(Ns,Ns)/p0;
jacrows.at(i)[{_id,gp*nvars_per_gp+constants::rho}] =
-(gamma0/rho0)*diagmat(pow(rho/rho0,gamma0-1));
TRACE(15,"SFSG");
}
break;
default:
tasmet_assert(false,"Not implemented htmodel");
}
i++;
TRACE(15,"SFSG");
// Equation of state
st = gas.rho(T,p) - rho;
residual.subvec(eq_offset+0*Ns,eq_offset+1*Ns-1) = cont;
residual.subvec(eq_offset+1*Ns,eq_offset+2*Ns-1) = mom;
residual.subvec(eq_offset+2*Ns,eq_offset+3*Ns-1) = en;
residual.subvec(eq_offset+3*Ns,eq_offset+4*Ns-1) = st;
TRACE(15,"SFSG");
jacrows.at(i)[{_id,gp*nvars_per_gp+constants::rho}] =
-eye(Ns,Ns);
jacrows.at(i)[{_id,gp*nvars_per_gp+constants::p}] =
diagmat(gas.drhodp(T,p));
jacrows.at(i)[{_id,gp*nvars_per_gp+constants::T}] =
diagmat(gas.drhodT(T,p));
*residual.at(i) = st;
TRACE(15,"SFSG");
i++;
}
eq_offset += number_eqs*Ns;
// Equation of state for the last node
st = gas.rho(Tp,pp) - rhop;
residual.subvec(eq_offset,eq_offset+Ns-1) = st;
*residual.at(i) = st;
jacrows.at(i)[{_id,(ngp()-1)*nvars_per_gp+constants::rho}] =
-eye(Ns,Ns);
jacrows.at(i)[{_id,(ngp()-1)*nvars_per_gp+constants::p}] =
diagmat(gas.drhodp(T,p));
jacrows.at(i)[{_id,(ngp()-1)*nvars_per_gp+constants::T}] =
diagmat(gas.drhodT(T,p));
i++;
// Two more equations for the last grid point in case
// the heat transfer model is not a transport equation.
if(_ductpb.htmodel() == pb::Isentropic) {
eq_offset += Ns;
d T0 = gas.T0();
d p0 = gas.p0();
d rho0 = gas.rho0();
@ -159,24 +203,43 @@ void Duct::residualJac(arma::subview_col<d> && residual) const {
en = p/p0 - pow(rho/rho0,gamma0);
residual.subvec(eq_offset,eq_offset+Ns-1) = en;
jacrows.at(i)[{_id,(ngp()-1)*nvars_per_gp+constants::p}] =
eye(Ns,Ns)/p0;
jacrows.at(i)[{_id,(ngp()-1)*nvars_per_gp+constants::rho}] =
-(gamma0/rho0)*diagmat(pow(rho/rho0,gamma0-1));
*residual.at(i) = en; i++;
}
}
PosId Duct::getDof(int varnr,int gp) const {
// Wraparound
if(gp<0) gp+=ngp();
// rho,u,T,p
// Ts maybe
us nvars_per_gp = (_ductpb.stempmodel()
== pb::HeatBalance ? 5 : 4);
return {_id,nvars_per_gp*gp+varnr};
}
vd Duct::getvart(int varnr,int gp) const {
TRACE(15,"Duct::getvart()");
const arma::subview_col<d> sol = sys.getSolution(_id);
TRACE(14,"Duct::getvart()");
const SegPositionMapper& sol = sys.getSolution(_id);
us Ns = sys.Ns();
// Wraparound
if(gp<0) gp+=ngp();
us vars_per_gp = 4;
vars_per_gp+= (_ductpb.stempmodel() == pb::HeatBalance ? 1 : 0);
// rho,u,T,p
// Ts maybe
us nvars_per_gp = (_ductpb.stempmodel()
== pb::HeatBalance ? 5 : 4);
return sol.subvec((gp*vars_per_gp+varnr)*Ns,
(gp*vars_per_gp+varnr+1)*Ns-1);
return *sol.at((gp*nvars_per_gp+varnr));
}
vd Duct::getvarx(int varnr,int t) const {
vd res(ngp());
@ -185,48 +248,44 @@ vd Duct::getvarx(int varnr,int t) const {
}
return res;
}
vd Duct::initialSolution() const {
void Duct::initialSolution(SegPositionMapper& sol) const {
TRACE(15,"Duct::initialSolution()");
vd initsol(getNDofs());
VARTRACE(15,initsol.size());
VARTRACE(15,sol.size());
us vars_per_gp = 4;
vars_per_gp+= (_ductpb.stempmodel() == pb::HeatBalance ? 1 : 0);
us Ns = sys.Ns();
us nvars_per_gp = 4;
nvars_per_gp+= (_ductpb.stempmodel() == pb::HeatBalance ? 1 : 0);
const Gas& gas = sys.gas();
us segdof = 0;
for(us i=0;i<ngp();i++){
VARTRACE(15,i);
// Initial density
initsol.subvec((i*vars_per_gp+0)*Ns,(i*vars_per_gp+1)*Ns-1) =
gas.rho0()+.01;
*sol.at(segdof) += gas.rho0()+0.1;
segdof++;
// Initial velocity
initsol.subvec((i*vars_per_gp+1)*Ns,(i*vars_per_gp+2)*Ns-1) =
0;
*sol.at(segdof) += 0.1;
segdof++;
// Initial Temperature
initsol.subvec((i*vars_per_gp+2)*Ns,(i*vars_per_gp+3)*Ns-1) =
_Tsprescribed(i);
*sol.at(segdof) += _Tsprescribed(i);
segdof++;
// Initial pressure
initsol.subvec((i*vars_per_gp+3)*Ns,(i*vars_per_gp+4)*Ns-1) =
gas.p0();
*sol.at(segdof) += gas.p0();
segdof++;
// Initial solid temperature, if not prescribed
if(_ductpb.stempmodel() != pb::Prescribed) {
initsol.subvec((i*vars_per_gp+4)*Ns,(i*vars_per_gp+5)*Ns-1) =
_Tsprescribed(i);
*sol.at(segdof) += _Tsprescribed(i);
segdof++;
}
}
return initsol;
}
us Duct::getNEqs() const {
@ -257,9 +316,9 @@ us Duct::getNDofs() const {
TRACE(15,"Duct::getNDofs()");
// rho,u,T,p
us nvars_per_gp = 4;
// Ts maybe
nvars_per_gp += (_ductpb.stempmodel() == pb::HeatBalance ? 1 : 0);
us nvars_per_gp = (_ductpb.stempmodel()
== pb::HeatBalance ? 5 : 4);
return nvars_per_gp*ngp();
}

View File

@ -12,6 +12,7 @@
#include "duct.pb.h"
#include "geom.h"
#include "tasmet_constants.h" // For the variable nrs
#include "jacobian.h"
class Equation;
class Drag;
@ -34,8 +35,9 @@ public:
vd Tsprescribed() const { return _Tsprescribed;}
// Initialize the solution to something sensible
vd initializeSolution(const TaSystem& sys);
void initialSolution(SegPositionMapper&) const;
virtual Duct* copy(const TaSystem&) const;
const Geom& geom() const;
@ -70,10 +72,10 @@ public:
vd getvarx(int varnr,int t) const;
d getvartx(int t,int gp) const;
// Solving
virtual void residualJac(arma::subview_col<d>&& residual) const;
vd initialSolution() const;
// Solving
virtual void residualJac(SegPositionMapper& residual,
SegJacRows& jac) const;
// virtual void getSolution(const TaSystem&,const us insertion_start) const;

View File

@ -35,20 +35,22 @@ AdiabaticWall::~AdiabaticWall() {
AdiabaticWall* AdiabaticWall::copy(const TaSystem& sys) const {
return new AdiabaticWall(sys,*this);
}
vd AdiabaticWall::initialSolution() const {
return vd();
}
void AdiabaticWall::residualJac(arma::subview_col<d>&& residual
) const {
TRACE(15,"AdiabaticWall::residual()");
void AdiabaticWall::residualJac(SegPositionMapper& residual,
SegJacRows& jac) const {
TRACE(15,"AdiabaticWall::residualJac()");
const Duct& duct = getDuct();
const pb::Duct& dpb = duct.getDuctPb();
us Ns = sys.Ns();
us i=0;
if(_side == pb::left) {
residual.subvec(0,Ns-1) = duct.ut(0);
*residual.at(i) = duct.ut(0);
jac.at(i)[duct.getDof(constants::u,0)].eye(Ns,Ns);
if(dpb.htmodel() != pb::Isentropic) {
// TODO: Put the boundary condition of zero heat flux here
// residual.subvec(Ns,2*Ns-1) =
@ -56,7 +58,8 @@ void AdiabaticWall::residualJac(arma::subview_col<d>&& residual
}
}
else {
residual.subvec(0,Ns-1) = duct.ut(-1);
*residual.at(i) = duct.ut(-1);
jac.at(i)[duct.getDof(constants::u,-1)].eye(Ns,Ns);
if(dpb.htmodel() != pb::Isentropic) {
// TODO: Put the boundary condition of zero heat flux here
// residual.subvec(Ns,2*Ns-1) = duct.Tt(sys,-1) - _T;

View File

@ -34,10 +34,8 @@ public:
~AdiabaticWall();
AdiabaticWall* copy(const TaSystem& sys) const;
vd initialSolution() const;
virtual void residualJac(arma::subview_col<d>&& residual
) const;
virtual void residualJac(SegPositionMapper& residual,
SegJacRows& jac) const;
// Return the total number of equations in this segment
virtual us getNEqs() const;
@ -50,11 +48,6 @@ public:
// Reset amplitude data in higher harmonics
// virtual void resetHarmonics() = 0;
// Fill Jacobian with values from the equations in this
// segment/connector.
virtual void jac(const TaSystem&,Jacobian&,us dof_start,us eq_start) const;
};
#endif // ADIABATICWALL_H

View File

@ -31,10 +31,10 @@ DuctBc* DuctBc::newDuctBc(const us id,
return new PressureBc(sys,id,dbc);
break;
}
// case pb::AdiabaticWall: {
// return new AdiabaticWall(id,sys,dbc);
// break;
// }
case pb::AdiabaticWall: {
return new AdiabaticWall(sys,id,dbc);
break;
}
default:
tasmet_assert(false,"Not implemented DuctBc");
break;

View File

@ -33,6 +33,8 @@ public:
const Duct& getDuct() const;
virtual void initialSolution(SegPositionMapper&) const {}
};

View File

@ -69,31 +69,28 @@ PressureBc::~PressureBc() {
PressureBc* PressureBc::copy(const TaSystem& sys) const {
return new PressureBc(sys,*this);
}
vd PressureBc::initialSolution() const {
return vd();
}
void PressureBc::residualJac(arma::subview_col<d>&& residual
) const {
void PressureBc::residualJac(SegPositionMapper& residual,
SegJacRows& jacrows) const {
TRACE(15,"PressureBc::residual()");
TRACE(15,"PressureBc::residualJac()");
const pb::Duct& dpb = getDuct().getDuctPb();
us Ns = sys.Ns();
const Duct& duct = getDuct();
if(_side == pb::left) {
residual.subvec(0,Ns-1) = duct.pt(0) - _p;
*residual.at(0) = duct.pt(0) - _p;
jacrows.at(0)[duct.getDof(constants::p,0)] = eye(Ns,Ns);
if(dpb.htmodel() != pb::Isentropic) {
residual.subvec(Ns,2*Ns-1) = duct.Tt(0) - _T;
// residual.subvec(Ns,2*Ns-1) = duct.Tt(0) - _T;
}
}
else {
residual.subvec(0,Ns-1) = duct.pt(-1) - _p;
*residual.at(0) = duct.pt(-1) - _p;
jacrows.at(0)[duct.getDof(constants::p,-1)] = eye(Ns,Ns);
if(dpb.htmodel() != pb::Isentropic) {
residual.subvec(Ns,2*Ns-1) = duct.Tt(-1) - _T;
// residual.subvec(Ns,2*Ns-1) = duct.Tt(-1) - _T;
}
}
}

View File

@ -38,10 +38,8 @@ public:
PressureBc* copy(const TaSystem&) const;
vd initialSolution() const;
virtual void residualJac(arma::subview_col<d>&& residual
) const;
virtual void residualJac(SegPositionMapper& residual,
SegJacRows& jac) const;
// Return the total number of equations in this segment
virtual us getNEqs() const;

View File

@ -21,11 +21,11 @@ using pb::air;
using pb::helium;
using pb::nitrogen;
#define element_wise(varname) \
vd varname_(T.size()); \
#define element_wise(function) \
vd function_(T.size()); \
for(us i=0;i<T.size();i++) \
varname_ = varname(T(i),p(i));\
return varname_
function_(i) = function(T(i),p(i)); \
return function_

View File

@ -34,27 +34,23 @@ void NewtonRaphson::start_implementation(GradientNonlinearSystem& system,
ResidualJac resjac;
system.residualJac(resjac);
const sdmat& jac = resjac.jacobian;
const vd& residual = resjac.residual;
vd dx;
#ifdef DEBUG_TASMET_SYSTEM
cout << "Initial residual: " << endl;
cout << residual << endl;
#endif // DEBUG_TASMET_SYSTEM
assert(jac.n_cols==residual.size());
assert(jac.n_rows==residual.size());
assert(resjac.jacobian.n_cols==resjac.residual.size());
assert(resjac.jacobian.n_rows==resjac.residual.size());
while (true) {
#ifdef DEBUG_TASMET_SYSTEM
cout << "Residual: ";
cout << residual << endl;
cout << resjac.residual << endl;
cout << dmat(resjac.jacobian) << endl;
#endif // DEBUG_TASMET_SYSTEM
dx = -1*_dampfac*arma::spsolve(jac,residual,"superlu");
TRACE(15,"Solving system of eqs");
dx = -1*_dampfac*arma::spsolve(resjac.jacobian,resjac.residual,"superlu");
TRACE(15,"Solving system of eqs done");
progress.rel_err = norm(dx);
guess += dx;
@ -64,12 +60,14 @@ void NewtonRaphson::start_implementation(GradientNonlinearSystem& system,
// Obtain a new residual and Jacobian matrix
system.residualJac(resjac);
progress.fun_err = norm(residual);
progress.fun_err = norm(resjac.residual);
progress.iteration++;
action = (*callback)(progress);
if(action==Stop){
TRACE(15,"Solution at stop:");
TRACE(15,guess);
break;
}

View File

@ -1,13 +0,0 @@
// jaccol.cpp
//
// last-edit-by: J.A. de Jong
//
// Description:
//
//////////////////////////////////////////////////////////////////////
#include "jaccol.h"
//////////////////////////////////////////////////////////////////////

View File

@ -1,50 +0,0 @@
// jaccol.h
//
// Author: J.A. de Jong
//
// Description:
// A column block of the Jacobian matrix
//////////////////////////////////////////////////////////////////////
#pragma once
#ifndef JACCOL_H
#define JACCOL_H
#include "tasmet_types.h"
/**
* A PosId is a specifier for the position in the global Jacobian
* matrix. Both considering the column as well as the row
*
*/
struct PosId {
int segno;
int segoffset;
};
class JacCol{ // Column block of Jacobian
public:
// For more ease of use, we make the members public.
PosId id; /**< The Id of this DOF */
dmat data; /**< The matrix block */
JacCol(PosId id): id(id){}
JacCol(PosId id,const dmat& data):id(id),data(data){}
JacCol& operator=(const JacCol& o) { id = o.id; data=o.data; return *this; }
JacCol(const JacCol& o): id(o.id),data(o.data){}
void prePostMultiply(const dmat& pre,const dmat& post){ data=pre*data*post;}
// Some operations on the data
JacCol operator-() { return JacCol(id,-data);}
JacCol& operator+=(const dmat& add) {data+=add; return *this;}
JacCol& operator*=(const double d) {data*=d; return *this;}
};
#endif // JACCOL_H
//////////////////////////////////////////////////////////////////////

View File

@ -2,14 +2,6 @@
#include "triplets.h"
#include "tasmet_tracer.h"
void Jacobian::operator+=(const Jacobian& other){
TRACE(2,"Jacobian::append()");
jacrows.insert(jacrows.end(),other.jacrows.begin(),other.jacrows.end());
}
void Jacobian::operator+=(const JacRow& other){
TRACE(2,"Jacobian::append()");
jacrows.push_back(other);
}
// Jacobian::operator TripletList() const{
// TRACE(18,"Jacobian::operator Tripletlist()");

View File

@ -8,25 +8,59 @@
#pragma once
#ifndef JACOBIAN_H
#define JACOBIAN_H
#include "tasmet_types.h"
#include "jacrow.h"
#include <unordered_map>
#include <map>
class TripletList;
/**
* A PosId is a specifier for the position in the global Jacobian
* matrix. Both considering the column as well as the row
*
*/
struct PosId {
us segno; /**< This is the segment number */
us segoffset; /**< This is the offset in the segment */
class Jacobian{
us _ndofs;
public:
Jacobian(us ndofs):_ndofs(ndofs){}
vector<JacRow> jacrows;
bool operator==(const PosId& other) const {
return (segno==other.segno) &&
(segoffset == other.segoffset);
}
void operator+=(const Jacobian&);
void operator+=(const JacRow&);
bool operator<(const PosId& other) const {
if(other.segno < segno) return true;
else if(other.segno > segno) return false;
else return (other.segoffset < segoffset);
operator TripletList() const;
}
};
/**
* To use the PosId in an unordered_map, it requires a custom hash
* function. This struct has a custom function to generate a hash from
* the given two integers.
*
*/
struct hash_PosId
{
std::size_t operator() ( const PosId& m ) const
{
const us a = m.segno+1 ;
const us b = m.segoffset+1 ;
return std::hash<us>()( a*b + (a+b) ) ;
}
};
typedef std::unordered_map<PosId,dmat,hash_PosId> JacRow;
typedef std::vector<JacRow> SegJacRows;
typedef std::map<us,SegJacRows> Jacobian;
typedef std::vector<vd*> SegPositionMapper;
typedef std::map<us, SegPositionMapper> GlobalPositionMapper;
#endif // JACOBIAN_H
//////////////////////////////////////////////////////////////////////

View File

@ -1,40 +0,0 @@
#include "jacobian.h"
#include "tasmet_variable.h"
#include "globalconf.h"
JacRow& JacRow::operator+=(const JacCol& j){
TRACE(10,"JacRow::operator+=(const JacCol& j)");
jaccols.push_back(j);
return *this;
}
JacRow& JacRow::operator*=(const d val){
TRACE(2,"Jacobian::operator*=()");
for(JacCol& col: jaccols)
col*=val;
return *this;
}
JacRow& JacRow::operator+=(const JacRow& other){
// Reserve some space
this->jaccols.reserve(this->jaccols.capacity()+other.jaccols.size()-this->jaccols.size());
for(const JacCol& col :other.jaccols)
(*this)+=col;
return *this;
}
JacRow JacRow::operator-() const{
TRACE(15,"JacRow::operator-()");
JacRow result(*this);
for (JacCol& jaccol : result.jaccols)
jaccol*=-1;
return result;
}
void JacRow::prePostMultiply(const dmat& pre,const dmat& post) {
for(JacCol& jaccol: jaccols)
jaccol.prePostMultiply(pre,post);
}

View File

@ -1,55 +0,0 @@
// jacrow.h
//
// Author: J.A. de Jong
//
// Description:
//
//////////////////////////////////////////////////////////////////////
#pragma once
#ifndef JACROW_H
#define JACROW_H
#include <vector>
#include "jaccol.h"
class JacRow{ // Row in Jacobian matrix
public:
PosId id; /**< Specifies the row for this
JacRow */
std::vector<JacCol> jaccols; /**< The columns in this row */
/**
* Initialize a Jacobian row with a single column block
*
* @param id The equation ID
* @param col The added column
*/
JacRow(PosId id,const JacCol& col):JacRow(id){jaccols.push_back(col);}
JacRow(PosId id): id(id){}
JacRow operator-() const;
JacRow& operator+=(const JacCol&);
JacRow& operator+=(const JacRow& jacrow);
JacRow& operator*=(const d val); // Multiply all terms with constant value
/**
* Pre- and postmultiply all Column blocks with the given
* matrices. Hence the new columns will be col_new = pre*col_old*post
*
* @param pre : The pre-multiply matrix
* @param post: The post-multiply matrix
*/
void prePostMultiply(const dmat& pre,const dmat& post);
};
#endif // JACROW_H
//////////////////////////////////////////////////////////////////////

View File

@ -15,9 +15,10 @@
#include "tasmet_types.h"
#include "tasmet_exception.h"
#include "jacobian.h"
// #include "phaseconstraint.h"
class Jacobian;
class GlobalConf;
class TaSystem;
@ -51,9 +52,10 @@ public:
*/
virtual Segment* copy(const TaSystem&) const = 0;
virtual vd initialSolution() const = 0;
virtual void initialSolution(SegPositionMapper&) const = 0;
virtual void residualJac(arma::subview_col<d>&& residual // Here we store the residual
virtual void residualJac(SegPositionMapper& residual,
SegJacRows& jacrows// Here we store the residual
) const=0;
// Get and set name

View File

@ -60,47 +60,8 @@ TaSystem::TaSystem(const pb::System& sys):
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();
}
else {
solution.subvec(dofend(i-1),dofend(i)-1) =
seg->initialSolution();
}
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++;
// }
// }
initSolRes();
}
TaSystem::TaSystem(const TaSystem& o):
@ -117,7 +78,89 @@ TaSystem::TaSystem(const TaSystem& o):
seg.second = seg.second->copy(*this);
if(!seg.second) throw TaSMETBadAlloc();
}
initSolRes();
}
void TaSystem::initSolRes() {
// Create the initial solution from the segments and store it
// here. Please be careful not to call any virtual functions!
vus ndofs = getNDofs();
vus neqs = getNEqs();
us Ns = this->Ns();
us total_dofs = arma::sum(ndofs);
us total_eqs = arma::sum(neqs);
if(total_dofs != total_eqs) {
throw TaSMETError("Number of equations does not match number of DOFS. "
"This is probably due to missing, or too much boundary conditions");
}
if(total_dofs*Ns > constants::maxndofs) {
stringstream error;
error << "Too many DOFS required. Problem too large. "
"Number of equations computed: ";
error << total_dofs*Ns;
throw TaSMETError(error);
}
_solution = zeros(total_dofs*Ns);
_residual = zeros(total_dofs*Ns)+arma::datum::nan;
d* solptr = _solution.memptr();
d* resptr = _residual.memptr();
us globalposdof=0;
us globalposeq=0;
// Loop over the segments, and for each dof in the segment, we
// allocate a vd, with its memory pointed to from the global
// solution pointer.
for(auto& seg_: _segs) {
us segid = seg_.first;
VARTRACE(15,segid);
for(us i=0;i< ndofs(segid); i++) {
// false: own memory (means the vd does not own the memory
// true: strict true means bound to the memory for its
// lifetime. Does not allow memory adjustments.
_solution_dofs[segid].push_back(new vd(&solptr[globalposdof*Ns],Ns,false,true));
globalposdof++;
VARTRACE(15,i);
}
// Set the initial solution
if(ndofs(segid)>0)
seg_.second->initialSolution(_solution_dofs.at(segid));
for(us i=0;i< neqs(segid); i++) {
// false: own memory (means the vd does not own the memory
// true: strict true means bound to the memory for its
// lifetime. Does not allow memory adjustments.
_residual_eqs[segid].push_back(new vd(&resptr[globalposeq*Ns],Ns,false,true));
_jac[segid].push_back(JacRow());
globalposeq++;
}
}
tasmet_assert(globalposdof == total_dofs,"Bug in assigning solution vectors");
tasmet_assert(globalposeq == total_eqs,"Bug in assigning residual vectors");
}
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
@ -156,56 +199,85 @@ int TaSystem::getArbitrateMassEq(const vus& neqs) const {
void TaSystem::residualJac(ResidualJac& resjac) 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);
int arbitrateMassEq = -1;//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);
_residual *= arma::datum::nan;
#endif
us i=0;
us segid;
const Segment* seg;
for(auto seg_: _segs) {
segid = seg_.first;
seg = seg_.second;
if(i==0) {
// Put the residual of the segment in the over-all residual
seg->residualJac(residual.subvec(0,eqsend(0)-1));
}
else {
seg->residualJac(residual.subvec(eqsend(i-1),eqsend(i)-1));
}
seg->residualJac(_residual_eqs[segid],_jac[segid]);
// Count the mass, add it
if(arbitrateMassEq!=-1) {
mass += seg->getMass();
}
i++;
}
}
us Ns = this->Ns();
vus neqs = getNEqs();
vus neqs_sum = arma::cumsum(neqs);
us total_neqs = arma::sum(neqs);
vus ndofs = getNDofs();
vus ndofs_sum = arma::cumsum(ndofs);
us total_ndofs = arma::sum(ndofs);
// Now we create the triplets
TripletList triplets(total_neqs*Ns);
for(auto& segjacrows : _jac) {
// The current segment number
us segno = segjacrows.first;
// The row offset for this segment
us rowoffset = (segno==0) ? 0 : neqs_sum(segno-1)*Ns;
for(auto& jacrow: segjacrows.second) {
for(auto& jaccol : jacrow) {
const PosId& id = jaccol.first;
us coloffset = (id.segno==0) ? 0 : ndofs_sum(segno-1)*Ns;
coloffset += id.segoffset;
coloffset*=Ns;
dmat& colmat = jaccol.second;
for(us i=0;i<Ns;i++){
us row = rowoffset + i;
for(us j=0;j<Ns;j++) {
us col = coloffset + j;
triplets.addTriplet(Triplet(row,col,colmat(i,j)));
}
}
} // For loop over the columns
rowoffset += Ns;
} // For loop over the rows for this segment
} // For loop over the segments
TRACE(15,"Obtained residual from all Segments");
@ -214,48 +286,33 @@ void TaSystem::residualJac(ResidualJac& resjac) const {
#endif // TASMET_DEBUG
// Exchange equation if we need to arbitrate mass
if(arbitrateMassEq!=-1) {
residual(arbitrateMassEq)=mass - _mass;
if(arbitrateMassEq>=0) {
_residual(arbitrateMassEq)=mass - _mass;
}
resjac.residual = residual;
resjac.jacobian = sdmat(triplets);
resjac.residual = _residual;
}
vd TaSystem::getSolution() const {
return _solution;
}
const arma::subview_col<d> 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);
}
const SegPositionMapper& TaSystem::getSolution(const us seg_id) const {
return _solution_dofs.at(seg_id);
}
vus TaSystem::getNDofs() const {
TRACE(0,"TaSystem::getNDofs()");
vus Ndofs(_segs.size());
us i=0;
for (auto seg : _segs) {
Ndofs(i)=seg.second->getNDofs();
i++;
Ndofs(seg.first)=seg.second->getNDofs();
}
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();
VARTRACE(15,Neqs(i));
i++;
Neqs(seg.first)=seg.second->getNEqs();
}
return Neqs;
}
@ -341,7 +398,19 @@ TaSystem::~TaSystem() {
cleanup();
}
void TaSystem::cleanup() {
purge(_segs);
for(auto& segdofs: _solution_dofs) {
for(vd* dof : segdofs.second){
delete dof;
}
}
for(auto& segdofs: _residual_eqs) {
for(vd* dof : segdofs.second){
delete dof;
}
}
}
//////////////////////////////////////////////////////////////////////

View File

@ -11,9 +11,9 @@
#include "system.h"
#include "globalconf.h"
#include "triplets.h"
#include "jacobian.h"
#include "gas.h"
#include "protobuf/system.pb.h"
#include <map>
#include <memory>
class Segment;
@ -28,21 +28,48 @@ protected:
std::unique_ptr<Gas> _gas;
mutable
vd _solution; /**< This column vector stores the
current solution. */
std::vector<vd> _dofs; /**< This vector of column vectors
stores columns of doubles that do
not own the memory they point
to. Instead, they use the memory of
_solution.*/
mutable
GlobalPositionMapper _solution_dofs; /**< This vector of column vectors
stores columns of doubles that do
not own the memory they point
to. Instead, they use the memory of
_solution.*/
vus _startdof; // Store the start DOFS for each segment
mutable
vd _residual;
mutable
GlobalPositionMapper _residual_eqs;
mutable
Jacobian _jac; /**< Storing the Jacobian brings the
hugh benefit of only allocating the
memory once. Once this is done, all
values can be updated during each
iteration. */
TaSystem& operator=(const TaSystem& other)=delete;
private:
/**
* Initializes the _solution and _solution_dofs vector. This
* should be done during construction of the object. The method is
* called from all constructors. Should be done after construction
* of the segments.
*
*/
void initSolRes();
public:
TaSystem(const TaSystem& o);
TaSystem(const pb::System&);
static TaSystem testSystem() {
return TaSystem(pb::System::default_instance());
}
@ -67,7 +94,7 @@ public:
vd getSolution() const;
// Obtain the solution vector for the Segment with given id
const arma::subview_col<d> getSolution(const us seg_id) const;
const SegPositionMapper& getSolution(const us seg_id) const;
virtual void updateSolution(const vd& sol) {_solution = sol; } // Update the solution