Added output of nodal reaction forces, and also for Lagrange grids

git-svn-id: http://svn.sintef.no/trondheim/IFEM/trunk@902 e10b68d5-8a6e-419e-a041-bce267b0401d
This commit is contained in:
kmo
2011-04-05 22:02:42 +00:00
committed by Knut Morten Okstad
parent a5eaefef22
commit 400e895709
28 changed files with 374 additions and 115 deletions

View File

@@ -41,6 +41,7 @@
\arg -nv \a nv : Number of visualization points per knot-span in v-direction
\arg -nw \a nw : Number of visualization points per knot-span in w-direction
\arg -skip2nd : Skip VTF-output of secondary solution fields
\arg -noEnergy : Skip integration of energy norms
\arg -saveInc \a dtSave : Time increment between each result save to VTF
\arg -dumpInc \a dtDump [raw] : Time increment between each solution dump
\arg -ignore \a p1, \a p2, ... : Ignore these patches in the analysis
@@ -65,12 +66,14 @@ int main (int argc, char** argv)
int form = SIM::TOTAL_LAGRANGE;
int nGauss = 4;
int format = -1;
int outPrec = 3;
int n[3] = { 2, 2, 2 };
std::vector<int> ignoredPatches;
double dtSave = 0.0;
double dtDump = 0.0;
bool dumpWithID = true;
bool skip2nd = false;
bool energy = true;
bool checkRHS = false;
bool fixDup = false;
bool twoD = false;
@@ -108,8 +111,12 @@ int main (int argc, char** argv)
n[2] = atoi(argv[++i]);
else if (!strcmp(argv[i],"-skip2nd"))
skip2nd = true;
else if (!strcmp(argv[i],"-noEnergy"))
energy = false;
else if (!strcmp(argv[i],"-saveInc") && i < argc-1)
dtSave = atof(argv[++i]);
else if (!strcmp(argv[i],"-outPrec") && i < argc-1)
outPrec = atoi(argv[++i]);
else if (!strcmp(argv[i],"-dumpInc") && i < argc-1)
{
dtDump = atof(argv[++i]);
@@ -291,11 +298,11 @@ int main (int argc, char** argv)
while (simulator.advanceStep(params))
{
// Solve the nonlinear FE problem at this load step
if (!simulator.solveStep(params,SIM::STATIC))
if (!simulator.solveStep(params,SIM::STATIC,"displacement",energy))
return 5;
// Print solution components at the user-defined points
simulator.dumpResults(params.time.t,std::cout);
simulator.dumpResults(params.time.t,std::cout,outPrec);
if (params.time.t + epsT*params.time.dt > nextDump)
{

View File

@@ -501,6 +501,27 @@ bool ASMbase::tesselate (ElementBlock&, const int*) const
}
bool ASMbase::getSolution (Matrix& sField, const Vector& locSol,
const IntVec& nodes) const
{
sField.resize(nf,nodes.size());
for (size_t i = 0; i < nodes.size(); i++)
if (nodes[i] < 1 || (size_t)nodes[i] > MLGN.size())
{
std::cerr <<" *** ASMbase::getSolution: Node #"<< nodes[i]
<<" is out of range [1,"<< MLGN.size() <<"]."<< std::endl;
return false;
}
else
{
for (unsigned char j = 0; j < nf; j++)
sField(j+1,i+1) = locSol[nf*(nodes[i]-1)+j];
}
return true;
}
bool ASMbase::evalSolution (Matrix&, const Vector&, const int*) const
{
std::cerr <<" *** ASMBase::evalSolution: Must be implemented in sub-class."

View File

@@ -229,7 +229,8 @@ public:
//! \param[in] xi Dimensionless parameters in range [0.0,1.0] of the point
//! \param[out] param The parameters of the point in the knot-span domain
//! \param[out] X The Cartesian coordinates of the point
virtual bool evalPoint(const double* xi, double* param, Vec3& X) const = 0;
//! \return Local node number within the patch that matches the point
virtual int evalPoint(const double* xi, double* param, Vec3& X) const = 0;
//! \brief Creates a standard FE model of this patch for visualization.
//! \param[out] grid The generated finite element grid
@@ -237,6 +238,13 @@ public:
//! \note The number of element nodes must be set in \a grid on input.
virtual bool tesselate(ElementBlock& grid, const int* npe) const;
//! \brief Extract the primary solution field at the specified nodes.
//! \param[out] sField Solution field
//! \param[in] locSol Solution vector local to current patch
//! \param[in] nodes 1-based local node numbers to extract solution for
bool getSolution(Matrix& sField, const Vector& locSol,
const IntVec& nodes) const;
//! \brief Evaluates the primary solution field at all visualization points.
//! \param[out] sField Solution field
//! \param[in] locSol Solution vector local to current patch

View File

@@ -603,18 +603,35 @@ bool ASMs1D::integrate (Integrand& integrand, int lIndex,
}
bool ASMs1D::evalPoint (const double* xi, double* param, Vec3& X) const
int ASMs1D::evalPoint (const double* xi, double* param, Vec3& X) const
{
if (!curv) return false;
if (!curv) return -1;
param[0] = (1.0-xi[0])*curv->startparam() + xi[0]*curv->endparam();
Go::Point X0;
curv->point(X0,param[0]);
for (unsigned char i = 0; i < nsd; i++)
X[i] = X0[i];
for (unsigned char d = 0; d < nsd; d++)
X[d] = X0[d];
return true;
// Check if this point matches any of the control points (nodes)
Vec3 Xnod;
size_t inod = 1;
RealArray::const_iterator cit = curv->coefs_begin();
for (int i = 0; cit != curv->coefs_end(); cit++, i++)
{
if (i < nsd) Xnod[i] = *cit;
if (i+1 == curv->dimension())
if (X.equal(Xnod,0.001))
return inod;
else
{
inod++;
i = -1;
}
}
return 0;
}

View File

@@ -126,7 +126,9 @@ public:
//! \param[in] xi Dimensionless parameter in range [0.0,1.0] of the point
//! \param[out] param The parameter of the point in the knot-span domain
//! \param[out] X The Cartesian coordinates of the point
virtual bool evalPoint(const double* xi, double* param, Vec3& X) const;
//! \return Local node number within the patch that matches the point, if any
//! \return 0 if no node (control point) matches this point
virtual int evalPoint(const double* xi, double* param, Vec3& X) const;
//! \brief Creates a line element model of this patch for visualization.
//! \param[out] grid The generated line grid

View File

@@ -281,6 +281,24 @@ bool ASMs1DLag::integrate (Integrand& integrand, int lIndex,
}
int ASMs1DLag::evalPoint (const double* xi, double* param, Vec3& X) const
{
if (!curv) return -1;
param[0] = (1.0-xi[0])*curv->startparam() + xi[0]*curv->endparam();
// Evaluate the parametric values of the nodes
RealArray u;
if (!this->getGridParameters(u,curv->order()-1)) return -1;
// Search for the closest node
size_t n = utl::find_closest(u,param[0]);
X = coord[n];
return 1+n;
}
bool ASMs1DLag::tesselate (ElementBlock& grid, const int*) const
{
size_t i, l;

View File

@@ -79,6 +79,13 @@ public:
// Post-processing methods
// =======================
//! \brief Evaluates the geometry at a specified point.
//! \param[in] xi Dimensionless parameters in range [0.0,1.0] of the point
//! \param[out] param The parameters of the point in the knot-span domain
//! \param[out] X The Cartesian coordinates of the point
//! \return Local node number within the patch that is closest to the point
virtual int evalPoint(const double* xi, double* param, Vec3& X) const;
//! \brief Creates a line element model of this patch for visualization.
//! \param[out] grid The generated line grid
//! \note The number of element nodes must be set in \a grid on input.

View File

@@ -1078,19 +1078,36 @@ bool ASMs2D::integrate (Integrand& integrand, int lIndex,
}
bool ASMs2D::evalPoint (const double* xi, double* param, Vec3& X) const
int ASMs2D::evalPoint (const double* xi, double* param, Vec3& X) const
{
if (!surf) return false;
if (!surf) return -2;
param[0] = (1.0-xi[0])*surf->startparam_u() + xi[0]*surf->endparam_u();
param[1] = (1.0-xi[1])*surf->startparam_v() + xi[1]*surf->endparam_v();
Go::Point X0;
surf->point(X0,param[0],param[1]);
for (unsigned char i = 0; i < nsd; i++)
X[i] = X0[i];
for (unsigned char d = 0; d < nsd; d++)
X[d] = X0[d];
return true;
// Check if this point matches any of the control points (nodes)
Vec3 Xnod;
size_t inod = 1;
RealArray::const_iterator cit = surf->coefs_begin();
for (int i = 0; cit != surf->coefs_end(); cit++, i++)
{
if (i < nsd) Xnod[i] = *cit;
if (i+1 == surf->dimension())
if (X.equal(Xnod,0.001))
return inod;
else
{
inod++;
i = -1;
}
}
return 0;
}

View File

@@ -199,7 +199,9 @@ public:
//! \param[in] xi Dimensionless parameters in range [0.0,1.0] of the point
//! \param[out] param The (u,v) parameters of the point in knot-span domain
//! \param[out] X The Cartesian coordinates of the point
virtual bool evalPoint(const double* xi, double* param, Vec3& X) const;
//! \return Local node number within the patch that matches the point, if any
//! \return 0 if no node (control point) matches this point
virtual int evalPoint(const double* xi, double* param, Vec3& X) const;
//! \brief Creates a quad element model of this patch for visualization.
//! \param[out] grid The generated quadrilateral grid

View File

@@ -386,6 +386,28 @@ bool ASMs2DLag::integrate (Integrand& integrand, int lIndex,
}
int ASMs2DLag::evalPoint (const double* xi, double* param, Vec3& X) const
{
if (!surf) return -2;
param[0] = (1.0-xi[0])*surf->startparam_u() + xi[0]*surf->endparam_u();
param[1] = (1.0-xi[1])*surf->startparam_v() + xi[1]*surf->endparam_v();
// Evaluate the parametric values of the nodes
RealArray u, v;
if (!this->getGridParameters(u,0,surf->order_u()-1)) return -2;
if (!this->getGridParameters(v,1,surf->order_v()-1)) return -2;
// Search for the closest node
size_t i = utl::find_closest(u,param[0]);
size_t j = utl::find_closest(v,param[1]);
size_t n = u.size()*j + i;
X = coord[n];
return 1+n;
}
bool ASMs2DLag::tesselate (ElementBlock& grid, const int* npe) const
{
const int p1 = surf->order_u();

View File

@@ -79,6 +79,13 @@ public:
// Post-processing methods
// =======================
//! \brief Evaluates the geometry at a specified point.
//! \param[in] xi Dimensionless parameters in range [0.0,1.0] of the point
//! \param[out] param The parameters of the point in the knot-span domain
//! \param[out] X The Cartesian coordinates of the point
//! \return Local node number within the patch that is closest to the point
virtual int evalPoint(const double* xi, double* param, Vec3& X) const;
//! \brief Creates a quad element model of this patch for visualization.
//! \param[out] grid The generated quadrilateral grid
//! \param[in] npe Number of visualization nodes over each knot span

View File

@@ -247,7 +247,7 @@ bool ASMs2DmxLag::integrate (Integrand& integrand,
// Evaluate the integrand and accumulate element contributions
fe.detJxW *= wg[i]*wg[j];
if (!integrand.evalInt(elmInt,fe,time,X))
if (!integrand.evalIntMx(elmInt,fe,time,X))
return false;
}
@@ -358,7 +358,7 @@ bool ASMs2DmxLag::integrate (Integrand& integrand, int lIndex,
// Evaluate the integrand and accumulate element contributions
fe.detJxW *= wg[i];
if (!integrand.evalBou(elmInt,fe,time,X,normal))
if (!integrand.evalBouMx(elmInt,fe,time,X,normal))
return false;
}

View File

@@ -1593,20 +1593,37 @@ bool ASMs3D::integrateEdge (Integrand& integrand, int lEdge,
}
bool ASMs3D::evalPoint (const double* xi, double* param, Vec3& X) const
int ASMs3D::evalPoint (const double* xi, double* param, Vec3& X) const
{
if (!svol) return false;
if (!svol) return -3;
for (int i = 0; i < 3; i++)
int i;
for (i = 0; i < 3; i++)
param[i] = (1.0-xi[i])*svol->startparam(i) + xi[i]*svol->endparam(i);
Go::Point X0;
svol->point(X0,param[0],param[1],param[2]);
X.x = X0[0];
X.y = X0[1];
X.z = X0[2];
for (i = 0; i < 3 && i < svol->dimension(); i++)
X[i] = X0[i];
return true;
// Check if this point matches any of the control points (nodes)
Vec3 Xnod;
size_t inod = 1;
RealArray::const_iterator cit = svol->coefs_begin();
for (i = 0; cit != svol->coefs_end(); cit++, i++)
{
if (i < 3) Xnod[i] = *cit;
if (i+1 == svol->dimension())
if (X.equal(Xnod,0.001))
return inod;
else
{
inod++;
i = -1;
}
}
return 0;
}

View File

@@ -264,7 +264,9 @@ public:
//! \param[in] xi Dimensionless parameters in range [0.0,1.0] of the point
//! \param[out] param The (u,v,w) parameters of the point in knot-span domain
//! \param[out] X The Cartesian coordinates of the point
virtual bool evalPoint(const double* xi, double* param, Vec3& X) const;
//! \return Local node number within the patch that matches the point, if any
//! \return 0 if no node (control point) matches this point
virtual int evalPoint(const double* xi, double* param, Vec3& X) const;
//! \brief Creates a hexahedron element model of this patch for visualization.
//! \param[out] grid The generated hexahedron grid

View File

@@ -544,6 +544,29 @@ bool ASMs3DLag::integrateEdge (Integrand& integrand, int lEdge,
}
int ASMs3DLag::evalPoint (const double* xi, double* param, Vec3& X) const
{
if (!svol) return -3;
// Evaluate the parametric values of the point and nodes
RealArray u[3];
for (int d = 0; d < 3; d++)
{
param[d] = (1.0-xi[d])*svol->startparam(d) + xi[d]*svol->endparam(d);
if (!this->getGridParameters(u[d],d,svol->order(d)-1)) return -3;
}
// Search for the closest node
size_t i = utl::find_closest(u[0],param[0]);
size_t j = utl::find_closest(u[1],param[1]);
size_t k = utl::find_closest(u[2],param[2]);
size_t n = u[0].size()*(u[1].size()*k + j) + i;
X = coord[n];
return 1+n;
}
bool ASMs3DLag::tesselate (ElementBlock& grid, const int* npe) const
{
const int p1 = svol->order(0);

View File

@@ -87,6 +87,13 @@ public:
// Post-processing methods
// =======================
//! \brief Evaluates the geometry at a specified point.
//! \param[in] xi Dimensionless parameters in range [0.0,1.0] of the point
//! \param[out] param The parameters of the point in the knot-span domain
//! \param[out] X The Cartesian coordinates of the point
//! \return Local node number within the patch that is closest to the point
virtual int evalPoint(const double* xi, double* param, Vec3& X) const;
//! \brief Creates a hexahedron element model of this patch for visualization.
//! \param[out] grid The generated hexahedron grid
//! \param[in] npe Number of visualization nodes over each knot span

View File

@@ -19,11 +19,12 @@
#include "slepceps.h"
#endif
LinAlgInit* LinAlgInit::instance;
int LinAlgInit::refs;
LinAlgInit* LinAlgInit::instance = 0;
int LinAlgInit::refs = 0;
LinAlgInit& LinAlgInit::Init(int argc, char** argv)
LinAlgInit& LinAlgInit::Init (int argc, char** argv)
{
if (!instance)
instance = new LinAlgInit(argc,argv);
@@ -31,18 +32,6 @@ LinAlgInit& LinAlgInit::Init(int argc, char** argv)
return *instance;
}
void LinAlgInit::increfs()
{
refs++;
}
void LinAlgInit::decrefs()
{
refs--;
if (!refs)
delete instance;
}
LinAlgInit::LinAlgInit (int argc, char** argv)
{

View File

@@ -1,4 +1,4 @@
// $Id: LinAlgInit.h,v 1.2 2011-01-02 15:50:35 kmo Exp $
// $Id$
//==============================================================================
//!
//! \file LinAlgInit.h
@@ -17,31 +17,37 @@
/*!
\brief Initializer for linear algebra packages.
\details This class is a reference-counted singleton. We need control over the
destruction order since the destructor calls \a PetscFinalize() which shuts
down MPI. Thus, the LinAlgInit object must be destroyed after all other
objects that do MPI calls in their destructor.
This cannot be guaranteed without the reference-counting since this class is
instanciated as a local variable in the \a main() scope of the applications.
*/
class LinAlgInit
{
//! \brief The constructor uses the command-line arguments to set up things.
LinAlgInit(int argc, char** argv);
public:
//! \brief This class is a ref-counted singleton. We need control over
// the destruction order since the destructor calls PetscFinalize()
// which shuts down MPI. Thus this object must be destroyed after
// objects that do MPI calls in their destructor.
// This we cannot guarantee without the ref-counting since this
// class is instanced as a local variable in the main() scope of
// applications.
static LinAlgInit& Init(int argc, char** argv);
//! \brief The destructor finalizes the linear algebra packages.
~LinAlgInit();
int myPid; //!< Processor ID in parallel simulations
static void increfs();
static void decrefs();
private:
static int refs;
//! \brief The constructor uses the command-line arguments to set up things.
LinAlgInit(int argc, char** argv);
//! \brief Increments the reference counter.
static void increfs() { ++refs; }
//! \brief Decrements the reference counter.
static void decrefs() { if (--refs == 0) delete instance; }
static LinAlgInit* instance;
//! \brief Instanciates the singleton LinAlgInit object.
static LinAlgInit& Init(int argc, char** argv);
int myPid; //!< Processor ID in parallel simulations
private:
static int refs; //!< Reference counter
static LinAlgInit* instance; //!< Pointer to the singleton object
};
#endif

View File

@@ -1,4 +1,4 @@
// $Id: LinSolParams.C,v 1.6 2011-02-08 12:45:08 rho Exp $
// $Id$
//==============================================================================
//!
//! \file LinSolParams.C
@@ -25,7 +25,7 @@ void LinSolParams::setDefault ()
// Use GMRES with ILU preconditioner as default
method = KSPGMRES;
prec = PCILU;
package = MAT_SOLVER_PETSC;
package = MAT_SOLVER_PETSC;
levels = 0;
overlap = 0;
nullspc = NONE;
@@ -126,8 +126,7 @@ bool LinSolParams::read (std::istream& is, int nparam)
nullspc = NONE;
}
else
{
else {
std::cerr <<" *** LinSolParams::read: Unknown keyword: "
<< cline << std::endl;
return false;

View File

@@ -1,4 +1,4 @@
// $Id: SAM.C,v 1.27 2011-02-05 18:07:50 kmo Exp $
// $Id$
//==============================================================================
//!
//! \file SAM.C
@@ -729,3 +729,21 @@ real SAM::normReact (const Vector& u, const Vector& rf) const
return retVal;
}
bool SAM::getNodalReactions (int inod, const Vector& rf, Vector& nrf) const
{
if (inod < 1 || inod > nnod) return false;
bool haveRF = false;
int ip = madof[inod-1]-1;
nrf.resize(madof[inod]-1-ip,true);
for (size_t i = 0; i < nrf.size(); i++, ip++)
if (msc[ip] < 0 && -msc[ip] <= (int)rf.size())
{
haveRF = true;
nrf[i] = rf(-msc[ip]);
}
return haveRF;
}

View File

@@ -1,4 +1,4 @@
// $Id: SAM.h,v 1.25 2011-02-08 12:45:46 rho Exp $
// $Id$
//==============================================================================
//!
//! \file SAM.h
@@ -101,7 +101,8 @@ public:
//! \param sysRHS The system right-hand-side load vector to be initialized
//! \param reactionForces Pointer to vector of nodal reaction forces
//! \return \e false if no free DOFs in the system, otherwise \e true
virtual bool initForAssembly(SystemVector& sysRHS, Vector* reactionForces = 0) const;
virtual bool initForAssembly(SystemVector& sysRHS,
Vector* reactionForces = 0) const;
//! \brief Adds an element stiffness matrix into the system stiffness matrix.
//! \param sysK The left-hand-side system stiffness matrix
@@ -204,6 +205,12 @@ public:
//! \param[in] u The (incremental) nodal displacement vector
//! \param[in] rf Compressed reaction force vector
virtual real normReact(const Vector& u, const Vector& rf) const;
//! \brief Returns a vector of reaction forces for a given node.
//! \param[in] inod Identifier for the node to get the reaction forces for
//! \param[in] rf Compressed reaction force vector for the entire model
//! \param[out] nrf Nodal reaction forces
//! \return \e true of the specified node has reaction forces
bool getNodalReactions(int inod, const Vector& rf, Vector& nrf) const;
protected:
//! \brief Initializes the DOF-to-equation connectivity array \a MEQN.

View File

@@ -125,7 +125,8 @@ bool NonLinSIM::advanceStep (SolvePrm& param)
}
bool NonLinSIM::solveStep (SolvePrm& param, SIM::SolutionMode mode)
bool NonLinSIM::solveStep (SolvePrm& param, SIM::SolutionMode mode,
const char* compName, bool energyNorm)
{
PROFILE1("NonLinSIM::solveStep");
@@ -160,7 +161,7 @@ bool NonLinSIM::solveStep (SolvePrm& param, SIM::SolutionMode mode)
return false;
model->setMode(SIM::RECOVERY);
if (!this->solutionNorms(param.time))
if (!this->solutionNorms(param.time,compName,energyNorm))
return false;
param.time.first = false;
@@ -324,7 +325,8 @@ bool NonLinSIM::updateConfiguration (SolvePrm& param)
}
bool NonLinSIM::solutionNorms (const TimeDomain& time, const char* compName)
bool NonLinSIM::solutionNorms (const TimeDomain& time, const char* compName,
bool energyNorm)
{
if (msgLevel < 0 || solution.empty()) return true;
@@ -334,8 +336,9 @@ bool NonLinSIM::solutionNorms (const TimeDomain& time, const char* compName)
double dMax[nsd];
double normL2 = model->solutionNorms(solution.front(),dMax,iMax);
if (!model->solutionNorms(time,solution,eNorm,gNorm))
gNorm.clear();
if (energyNorm)
if (!model->solutionNorms(time,solution,eNorm,gNorm))
gNorm.clear();
if (myPid == 0)
{
@@ -426,9 +429,9 @@ void NonLinSIM::dumpStep (int iStep, double time, std::ostream& os,
}
bool NonLinSIM::dumpResults (double time, std::ostream& os) const
bool NonLinSIM::dumpResults (double time, std::ostream& os, int precision) const
{
return model->dumpResults(solution.front(),time,os);
return model->dumpResults(solution.front(),time,os,precision);
}

View File

@@ -74,7 +74,11 @@ public:
//! \brief Solves the nonlinear equations by Newton-Raphson iterations.
//! \param param Solution algorithm parameters
//! \param[in] mode Solution mode to use for this step
bool solveStep(SolvePrm& param, SIM::SolutionMode mode = SIM::STATIC);
//! \param[in] compName Solution name to be used in the norm output
//! \param[in] energyNorm If \e true, integrate energy norm of the solution
bool solveStep(SolvePrm& param, SIM::SolutionMode mode = SIM::STATIC,
const char* compName = "displacement",
bool energyNorm = false);
//! \brief Enum describing the norm used for convergence checks.
enum CNORM { L2, ENERGY };
@@ -86,8 +90,9 @@ public:
//! \brief Computes and prints some solution norm quantities.
//! \param[in] time Parameters for nonlinear/time-dependent simulations
//! \param[in] compName Solution name to be used in the norm output
//! \param[in] energyNorm If \e true, integrate energy norm of the solution
bool solutionNorms(const TimeDomain& time,
const char* compName = "displacement");
const char* compName, bool energyNorm);
//! \brief Saves the converged results to VTF file of a given load/time step.
//! \param[in] iStep Load/time step identifier
@@ -107,7 +112,8 @@ public:
//! \brief Dumps solution variables at user-defined points.
//! \param[in] time Current time/load parameter
//! \param[in] os The output stream to write the solution to
bool dumpResults(double time, std::ostream& os) const;
//! \param[in] precision Number of digits after the decimal point
bool dumpResults(double time, std::ostream& os, int precision = 3) const;
//! \brief Returns a const reference to current solution vector.
const Vector& getSolution() const { return solution.front(); }

View File

@@ -142,9 +142,9 @@ bool SIMbase::parse (char* keyWord, std::istream& is)
std::cout <<"\n\tPoint "<< i+1 <<": P"<< myPoints[i].patch <<" xi =";
for (int j = 0; j < 3 && (cline = strtok(NULL," ")); j++)
{
myPoints[i].param[j] = atof(cline);
myPoints[i].par[j] = atof(cline);
if (myPid == 0)
std::cout <<' '<< myPoints[i].param[j];
std::cout <<' '<< myPoints[i].par[j];
}
}
if (myPid == 0 && nres > 0)
@@ -306,11 +306,11 @@ bool SIMbase::preprocess (const std::vector<int>& ignoredPatches, bool fixDup)
int pid = this->getLocalPatchIndex(p->patch);
if (pid < 1 || myModel[pid-1]->empty())
p = myPoints.erase(p);
else if ((p->inod = myModel[pid-1]->evalPoint(p->par,p->par,p->X)) < 0)
p = myPoints.erase(p);
else
{
p->npar = myModel[pid-1]->getNoParamDim();
myModel[pid-1]->evalPoint(p->param,p->param,p->X);
std::cout <<"\nResult point #"<< 1+(int)(p-myPoints.begin())
<<": patch #"<< p->patch;
switch (p->npar) {
@@ -318,11 +318,12 @@ bool SIMbase::preprocess (const std::vector<int>& ignoredPatches, bool fixDup)
case 2: std::cout <<" (u,v)=("; break;
case 3: std::cout <<" (u,v,w)=("; break;
}
std::cout << p->param[0];
std::cout << p->par[0];
for (unsigned char c = 1; c < p->npar; c++)
std::cout <<','<< p->param[c];
std::cout <<','<< p->par[c];
if (p->npar > 1) std::cout <<')';
std::cout <<", X = "<< p->X;
if (p->inod > 0) std::cout <<", node #"<< p->inod;
std::cout <<", X = "<< p->X;
p++;
}
}
@@ -1355,35 +1356,47 @@ bool SIMbase::dumpResults (const Vector& psol, double time, std::ostream& os,
size_t i, j, k;
Matrix sol1, sol2;
Vector reactionFS;
const Vector* reactionForces = myEqSys->getReactions();
for (i = 0; i < myModel.size(); i++)
{
if (myModel[i]->empty()) continue; // skip empty patches
ResPointVec::const_iterator p;
std::vector<size_t> points;
std::vector<int> points;
RealArray params[3];
// Find all evaluation points within this patch, if any
for (j = 0, p = myPoints.begin(); p != myPoints.end(); j++, p++)
if (this->getLocalPatchIndex(p->patch) == (int)(i+1))
{
points.push_back(j+1);
for (k = 0; k < myModel[i]->getNoParamDim(); k++)
params[k].push_back(p->param[k]);
}
if (discretization == Spline)
{
points.push_back(p->inod > 0 ? p->inod : -(j+1));
for (k = 0; k < myModel[i]->getNoParamDim(); k++)
params[k].push_back(p->par[k]);
}
else if (p->inod > 0)
points.push_back(p->inod);
if (points.empty()) continue; // no points in this patch
// Evaluate the primary solution variables
myModel[i]->extractNodeVec(psol,myProblem->getSolution());
if (!myModel[i]->evalSolution(sol1,myProblem->getSolution(),params,false))
return false;
if (discretization == Spline)
{
// Evaluate the primary solution variables
if (!myModel[i]->evalSolution(sol1,myProblem->getSolution(),params,false))
return false;
// Evaluate the secondary solution variables
LocalSystem::patch = i;
if (!myModel[i]->evalSolution(sol2,*myProblem,params,false))
return false;
// Evaluate the secondary solution variables
LocalSystem::patch = i;
if (!myModel[i]->evalSolution(sol2,*myProblem,params,false))
return false;
}
else
// Extract nodal primary solution variables
if (!myModel[i]->getSolution(sol1,myProblem->getSolution(),points))
return false;
// Formatted output, use scientific notation with fixed field width
std::streamsize flWidth = 8 + outputPrecision;
@@ -1391,13 +1404,32 @@ bool SIMbase::dumpResults (const Vector& psol, double time, std::ostream& os,
std::ios::fmtflags oldF = os.flags(std::ios::scientific | std::ios::right);
for (j = 0; j < points.size(); j++)
{
os <<" Result point #"<< points[j];
os <<": sol1 =";
if (points[j] > 0)
{
points[j] = myModel[i]->getNodeID(points[j]);
os <<" Node #"<< points[j] <<":\tsol1 =";
}
else
os <<" Point #"<< -points[j] <<":\tsol1 =";
for (k = 1; k <= sol1.rows(); k++)
os << std::setw(flWidth) << sol1(k,j+1);
os <<" sol2 =";
for (k = 1; k <= sol2.rows(); k++)
os << std::setw(flWidth) << sol2(k,j+1);
if (discretization == Spline)
{
os <<" sol2 =";
for (k = 1; k <= sol2.rows(); k++)
os << std::setw(flWidth) << sol2(k,j+1);
}
if (reactionForces && points[j] > 0)
// Print nodal reaction forces for nodes with prescribed DOFs
if (mySam->getNodalReactions(points[j],*reactionForces,reactionFS))
{
os <<"\n\t\treac =";
for (k = 0; k < reactionFS.size(); k++)
os << std::setw(flWidth) << reactionFS[k];
}
os << std::endl;
}
os.precision(oldPrec);

View File

@@ -51,12 +51,13 @@ struct Mode
struct ResultPoint
{
unsigned char npar; //!< Number of parameters
size_t patch; //!< Patch index [0,nPatch>
double param[3]; //!< Parameters of the point (u,v,w)
Vec3 X; //!< Spatial coordinates of the point
unsigned char npar; //!< Number of parameters
size_t patch; //!< Patch index [0,nPatch>
int inod; //!< Local node number of the closest node
double par[3]; //!< Parameters of the point (u,v,w)
Vec3 X; //!< Spatial coordinates of the point
// \brief Default constructor.
ResultPoint() : npar(0), patch(0) { param[0] = param[1] = param[2] = 0.0; }
ResultPoint() : npar(0), patch(0), inod(0) { par[0] = par[1] = par[2] = 0.0; }
};
typedef std::vector<ResultPoint> ResPointVec; //!< Result point container
@@ -154,11 +155,6 @@ public:
bool assembleSystem(const TimeDomain& time, const Vectors& pSol = Vectors(),
bool newLHSmatrix = true);
//! \brief Finalizes system assembly.
//TODO: This HAS to be called from subclasses if assembleSystem is overridden.
// This need to be fixed, probably through a wrapper function.
bool finalizeAssembly(bool newLHSmatrix);
//! \brief Administers assembly of the linear equation system.
//! \param[in] pSol Previous primary solution vectors in DOF-order
//!
@@ -238,6 +234,7 @@ public:
//! spline basis to obtain the control point values of the secondary solution.
bool project(Vector& psol);
// Post-processing methods
// =======================
@@ -363,15 +360,18 @@ protected:
//! \brief Initializes for integration of Neumann terms for a given property.
virtual bool initNeumann(size_t) { return true; }
//! \brief Extract local solution vector(s) for a given patch.
//! \brief Reads a LinSolParams object from the given stream.
//! \details This method helps with encapsulating PETSc in libIFEM.
void readLinSolParams(std::istream& is, int npar);
//! \brief Finalizes the system assembly.
bool finalizeAssembly(bool newLHSmatrix);
//! \brief Extracts local solution vector(s) for the given patch.
//! \param[in] patch Pointer to the patch to extract solution vectors for
//! \param[in] sol Global primary solution vectors in DOF-order
void extractPatchSolution(const ASMbase* patch, const Vectors& sol);
//! \brief Read a LinSolParams object from the given stream.
//! \details This method helps with encapsulating PETSc in libIFEM.
void readLinSolParams(std::istream& is, int npar);
public:
//! \brief Enum defining the available discretization methods.
enum Discretization { Spline, Lagrange, Spectral };

View File

@@ -71,7 +71,7 @@ Tensor& Tensor::operator= (const Tensor& T)
else
ndim = n;
for (t_ind i = 1; i <= ndim; i++)
for (t_ind j = (this->symmetric() ? i : 1); j <= n; j++)
for (t_ind j = (this->symmetric() ? i : 1); j <= ndim; j++)
v[this->index(i,j)] = T(i,j);
}

View File

@@ -189,3 +189,17 @@ void utl::Pascal (int p, real x, real y, real z, std::vector<real>& phi)
phi.push_back(a);
}
}
size_t utl::find_closest (const std::vector<real>& a, real v)
{
// The lower_bound function uses binary search to find the index of the value.
// Thus, this works only when the vector a is sorted in increasing order.
size_t i = std::lower_bound(a.begin(),a.end(),v) - a.begin();
if (i > 0 && i < a.size())
return a[i]-v < v-a[i-1] ? i : i-1;
else if (i == 0)
return 0;
else
return i-1;
}

View File

@@ -89,6 +89,14 @@ namespace utl
void Pascal(int p, real x, real y, std::vector<real>& phi);
//! \brief Evaluates the monomials of Pascal's triangle in 3D for order \a p.
void Pascal(int p, real x, real y, real z, std::vector<real>& phi);
//! \brief Searches for a real value in an ordered array of reals.
//! \param[in] a The array of real values
//! \param[in] v The value to search for
//! \return 0-based index of the closest array value.
//! \note It is assumed that the array \a a is sorted in encreasing order on
//! input. If this is not the case the method will deliver incorrect result.
size_t find_closest(const std::vector<real>& a, real v);
}
#endif