added: allow use of automatic differentation in analytic solutions
This commit is contained in:
parent
cca533fa1c
commit
abb21feef7
|
@ -208,6 +208,9 @@ bool SIMbase::preprocess (const IntVec& ignored, bool fixDup)
|
||||||
static int substep = 10;
|
static int substep = 10;
|
||||||
this->printHeading(substep);
|
this->printHeading(substep);
|
||||||
|
|
||||||
|
if (mySol)
|
||||||
|
mySol->setupSecondarySolutions();
|
||||||
|
|
||||||
// Perform some sub-class specific pre-preprocessing, if any
|
// Perform some sub-class specific pre-preprocessing, if any
|
||||||
this->preprocessA();
|
this->preprocessA();
|
||||||
|
|
||||||
|
|
|
@ -17,13 +17,51 @@
|
||||||
#include "Utilities.h"
|
#include "Utilities.h"
|
||||||
#include "IFEM.h"
|
#include "IFEM.h"
|
||||||
#include "tinyxml.h"
|
#include "tinyxml.h"
|
||||||
|
|
||||||
|
#include <autodiff/reverse/var.hpp>
|
||||||
|
|
||||||
#ifdef HAS_HDF5
|
#ifdef HAS_HDF5
|
||||||
#include "ProcessAdm.h"
|
|
||||||
#include "HDF5Writer.h"
|
|
||||||
#include "FieldFunctions.h"
|
#include "FieldFunctions.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
//! \brief Function returning the gradient of a scalar or vector function.
|
||||||
|
template<class FromFunc, class ToFunc, class Ret>
|
||||||
|
class GradientFunc : public ToFunc
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! \brief The constructor initializes the function to use.
|
||||||
|
GradientFunc(const FromFunc& f) : func(f) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//! \brief Evaluates the gradient in a point.
|
||||||
|
Ret evaluate(const Vec3& X) const { return func.gradient(X); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const FromFunc& func; //!< Reference to scalar/vector function
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief Specialization for symmetric tensors.
|
||||||
|
//! \details We need to construct a symmtensor from the returned tensor.
|
||||||
|
template<>
|
||||||
|
SymmTensor GradientFunc<VecFunc,STensorFunc,SymmTensor>::evaluate(const Vec3& X) const
|
||||||
|
{
|
||||||
|
Tensor tmp = func.gradient(X);
|
||||||
|
const size_t nsd = tmp.dim();
|
||||||
|
SymmTensor ret(nsd);
|
||||||
|
for (size_t i = 1; i <= nsd; ++i)
|
||||||
|
for (size_t j = i; j <= nsd; ++j)
|
||||||
|
ret(i,j) = tmp(i,j);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
AnaSol::AnaSol (RealFunc* s1, VecFunc* s2,
|
AnaSol::AnaSol (RealFunc* s1, VecFunc* s2,
|
||||||
VecFunc* v1, TensorFunc* v2, STensorFunc* v3)
|
VecFunc* v1, TensorFunc* v2, STensorFunc* v3)
|
||||||
: vecSol(v1), vecSecSol(v2), stressSol(v3)
|
: vecSol(v1), vecSecSol(v2), stressSol(v3)
|
||||||
|
@ -92,8 +130,15 @@ AnaSol::AnaSol (const TiXmlElement* elem, bool scalarSol)
|
||||||
const char* type = elem->Attribute("type");
|
const char* type = elem->Attribute("type");
|
||||||
if (type && !strcasecmp(type,"fields"))
|
if (type && !strcasecmp(type,"fields"))
|
||||||
this->parseFieldFunctions(elem,scalarSol);
|
this->parseFieldFunctions(elem,scalarSol);
|
||||||
|
else {
|
||||||
|
bool useAD = false;
|
||||||
|
utl::getAttribute(elem, "autodiff", useAD);
|
||||||
|
utl::getAttribute(elem, "symmetric", symmetric);
|
||||||
|
if (useAD)
|
||||||
|
this->parseExpressionFunctions<autodiff::var>(elem,scalarSol);
|
||||||
else
|
else
|
||||||
this->parseExpressionFunctions(elem,scalarSol);
|
this->parseExpressionFunctions<Real>(elem,scalarSol);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,8 +173,13 @@ void AnaSol::initPatch (size_t pIdx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Scalar>
|
||||||
void AnaSol::parseExpressionFunctions (const TiXmlElement* elem, bool scalarSol)
|
void AnaSol::parseExpressionFunctions (const TiXmlElement* elem, bool scalarSol)
|
||||||
{
|
{
|
||||||
|
using EvalF = EvalFuncSpatial<Scalar>;
|
||||||
|
using VecF = EvalMultiFunction<VecFunc,Vec3,Scalar>;
|
||||||
|
using TensorF = EvalMultiFunction<TensorFunc,Tensor,Scalar>;
|
||||||
|
using STensorF = EvalMultiFunction<STensorFunc,SymmTensor,Scalar>;
|
||||||
std::string variables;
|
std::string variables;
|
||||||
const TiXmlElement* var = elem->FirstChildElement("variables");
|
const TiXmlElement* var = elem->FirstChildElement("variables");
|
||||||
if (var && var->FirstChild())
|
if (var && var->FirstChild())
|
||||||
|
@ -168,16 +218,16 @@ void AnaSol::parseExpressionFunctions (const TiXmlElement* elem, bool scalarSol)
|
||||||
if (scalarSol)
|
if (scalarSol)
|
||||||
{
|
{
|
||||||
if (type == "expression") {
|
if (type == "expression") {
|
||||||
scalSol.push_back(new EvalFunction((variables+primary).c_str()));
|
scalSol.push_back(new EvalF((variables+primary).c_str()));
|
||||||
parseDerivatives(static_cast<EvalFunction*>(scalSol.back()),prim);
|
parseDerivatives(static_cast<EvalF*>(scalSol.back()),prim);
|
||||||
} else
|
} else
|
||||||
scalSol.push_back(utl::parseRealFunc(primary,type,false));
|
scalSol.push_back(utl::parseRealFunc(primary,type,false));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (type == "expression") {
|
if (type == "expression") {
|
||||||
vecSol = new VecFuncExpr(primary,variables);
|
vecSol = new VecF(primary,variables);
|
||||||
parseDerivatives(static_cast<VecFuncExpr*>(vecSol),prim);
|
parseDerivatives(static_cast<VecF*>(vecSol),prim);
|
||||||
} else
|
} else
|
||||||
vecSol = utl::parseVecFunc(primary, type);
|
vecSol = utl::parseVecFunc(primary, type);
|
||||||
}
|
}
|
||||||
|
@ -190,9 +240,9 @@ void AnaSol::parseExpressionFunctions (const TiXmlElement* elem, bool scalarSol)
|
||||||
utl::getAttribute(prim, "type", type);
|
utl::getAttribute(prim, "type", type);
|
||||||
std::string prType = (type == "expression" ? "" : "("+type+") ");
|
std::string prType = (type == "expression" ? "" : "("+type+") ");
|
||||||
std::string primary = prim->FirstChild()->Value();
|
std::string primary = prim->FirstChild()->Value();
|
||||||
IFEM::cout <<"\tScalar Primary " << prType << "=" << primary << std::endl;
|
IFEM::cout <<"\tScalar Primary" << prType << "=" << primary << std::endl;
|
||||||
if (type == "expression")
|
if (type == "expression")
|
||||||
scalSol.push_back(new EvalFunction((variables+primary).c_str()));
|
scalSol.push_back(new EvalF((variables+primary).c_str()));
|
||||||
else
|
else
|
||||||
scalSol.push_back(utl::parseRealFunc(primary, type, false));
|
scalSol.push_back(utl::parseRealFunc(primary, type, false));
|
||||||
prim = prim->NextSiblingElement("scalarprimary");
|
prim = prim->NextSiblingElement("scalarprimary");
|
||||||
|
@ -209,18 +259,18 @@ void AnaSol::parseExpressionFunctions (const TiXmlElement* elem, bool scalarSol)
|
||||||
if (scalarSol)
|
if (scalarSol)
|
||||||
{
|
{
|
||||||
if (type == "expression") {
|
if (type == "expression") {
|
||||||
scalSecSol.push_back(new VecFuncExpr(secondary,variables));
|
scalSecSol.push_back(new VecF(secondary,variables));
|
||||||
parseDerivatives(static_cast<VecFuncExpr*>(scalSecSol.back()),sec);
|
parseDerivatives(static_cast<VecF*>(scalSecSol.back()),sec);
|
||||||
} else
|
} else
|
||||||
scalSecSol.push_back(utl::parseVecFunc(secondary, type));
|
scalSecSol.push_back(utl::parseVecFunc(secondary, type));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (type == "expression")
|
if (type == "expression") {
|
||||||
vecSecSol = new TensorFuncExpr(secondary,variables);
|
vecSecSol = new TensorF(secondary,variables);
|
||||||
else
|
parseDerivatives(static_cast<TensorF*>(vecSecSol),sec);
|
||||||
|
} else
|
||||||
vecSecSol = utl::parseTensorFunc(secondary, type);
|
vecSecSol = utl::parseTensorFunc(secondary, type);
|
||||||
parseDerivatives(static_cast<TensorFuncExpr*>(vecSecSol),sec);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +282,7 @@ void AnaSol::parseExpressionFunctions (const TiXmlElement* elem, bool scalarSol)
|
||||||
std::string secondary = sec->FirstChild()->Value();
|
std::string secondary = sec->FirstChild()->Value();
|
||||||
IFEM::cout <<"\tScalar Secondary="<< secondary << std::endl;
|
IFEM::cout <<"\tScalar Secondary="<< secondary << std::endl;
|
||||||
if (type == "expression")
|
if (type == "expression")
|
||||||
scalSecSol.push_back(new VecFuncExpr(secondary,variables));
|
scalSecSol.push_back(new VecF(secondary,variables));
|
||||||
else
|
else
|
||||||
scalSecSol.push_back(utl::parseVecFunc(secondary, type));
|
scalSecSol.push_back(utl::parseVecFunc(secondary, type));
|
||||||
sec = sec->NextSiblingElement("scalarsecondary");
|
sec = sec->NextSiblingElement("scalarsecondary");
|
||||||
|
@ -241,10 +291,11 @@ void AnaSol::parseExpressionFunctions (const TiXmlElement* elem, bool scalarSol)
|
||||||
const TiXmlElement* stress = elem->FirstChildElement("stress");
|
const TiXmlElement* stress = elem->FirstChildElement("stress");
|
||||||
if (stress && stress->FirstChild())
|
if (stress && stress->FirstChild())
|
||||||
{
|
{
|
||||||
|
symmetric = true;
|
||||||
std::string sigma = stress->FirstChild()->Value();
|
std::string sigma = stress->FirstChild()->Value();
|
||||||
IFEM::cout <<"\tStress="<< sigma << std::endl;
|
IFEM::cout <<"\tStress="<< sigma << std::endl;
|
||||||
stressSol = new STensorFuncExpr(sigma,variables);
|
stressSol = new STensorF(sigma,variables);
|
||||||
parseDerivatives(static_cast<STensorFuncExpr*>(stressSol),stress);
|
parseDerivatives(static_cast<STensorF*>(stressSol),stress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,3 +361,23 @@ void AnaSol::parseFieldFunctions (const TiXmlElement* elem, bool scalarSol)
|
||||||
<<", no fields read."<< std::endl;
|
<<", no fields read."<< std::endl;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AnaSol::setupSecondarySolutions ()
|
||||||
|
{
|
||||||
|
// if we are given a stress sol, no scalar secondaries should be registered.
|
||||||
|
// this is tailored to assumptions in elasticity applications.
|
||||||
|
if (!stressSol && !scalSol.empty()) {
|
||||||
|
scalSecSol.resize(scalSol.size());
|
||||||
|
for (size_t i = 0; i < scalSol.size(); ++i)
|
||||||
|
if (!scalSecSol[i])
|
||||||
|
scalSecSol[i] = new GradientFunc<RealFunc,VecFunc,Vec3>(*scalSol[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vecSol) {
|
||||||
|
if (symmetric && !stressSol)
|
||||||
|
stressSol = new GradientFunc<VecFunc,STensorFunc,SymmTensor>(*vecSol);
|
||||||
|
else if (!symmetric && !vecSecSol)
|
||||||
|
vecSecSol = new GradientFunc<VecFunc,TensorFunc,Tensor>(*vecSol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -123,14 +123,22 @@ public:
|
||||||
//! \brief Sets the patch to use.
|
//! \brief Sets the patch to use.
|
||||||
void initPatch(size_t pIdx);
|
void initPatch(size_t pIdx);
|
||||||
|
|
||||||
|
//! \brief Make sure we have a secondary solution.
|
||||||
|
//! \details If none is given, we use derivation (automatic or finite difference)
|
||||||
|
//! to obtain one.
|
||||||
|
virtual void setupSecondarySolutions();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! \brief Parses expression functions from XML definition.
|
//! \brief Parses expression functions from XML definition.
|
||||||
|
template<class Scalar>
|
||||||
void parseExpressionFunctions(const TiXmlElement* elem, bool scalarSol);
|
void parseExpressionFunctions(const TiXmlElement* elem, bool scalarSol);
|
||||||
|
|
||||||
//! \brief Parses field functions from XML definition.
|
//! \brief Parses field functions from XML definition.
|
||||||
void parseFieldFunctions(const TiXmlElement* elem, bool scalarSol);
|
void parseFieldFunctions(const TiXmlElement* elem, bool scalarSol);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool symmetric = false; //!< True to use symmetric secondary solution
|
||||||
|
|
||||||
std::vector<RealFunc*> scalSol; //!< Primary scalar solution fields
|
std::vector<RealFunc*> scalSol; //!< Primary scalar solution fields
|
||||||
std::vector<VecFunc*> scalSecSol; //!< Secondary scalar solution fields
|
std::vector<VecFunc*> scalSecSol; //!< Secondary scalar solution fields
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include <autodiff/reverse/var.hpp>
|
#include <autodiff/reverse/var.hpp>
|
||||||
|
|
||||||
|
|
||||||
template<> int EvalFunc::numError = 0;
|
template<> int EvalFuncScalar<Real>::numError = 0; //!< Explicit instantiation
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -90,7 +90,7 @@ void ExprException (const ExprEval::Exception& exc, const char* task,
|
||||||
std::cerr <<": Unknown exception";
|
std::cerr <<": Unknown exception";
|
||||||
}
|
}
|
||||||
std::cerr << std::endl;
|
std::cerr << std::endl;
|
||||||
EvalFunc::numError++;
|
EvalFuncScalar<Real>::numError++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -99,14 +99,16 @@ class EvalFuncSpatial : public RealFunc
|
||||||
Scalar* z; //!< Z-coordinate
|
Scalar* z; //!< Z-coordinate
|
||||||
Scalar* t; //!< Time
|
Scalar* t; //!< Time
|
||||||
|
|
||||||
|
//! \brief Returns a const ref to a member.
|
||||||
|
//! \param dir One-based index to member
|
||||||
const Scalar& get(int dir) const
|
const Scalar& get(int dir) const
|
||||||
{
|
{
|
||||||
switch (dir) {
|
switch (dir) {
|
||||||
default:
|
|
||||||
case 1: return *x;
|
case 1: return *x;
|
||||||
case 2: return *y;
|
case 2: return *y;
|
||||||
case 3: return *z;
|
case 3: return *z;
|
||||||
case 4: return *t;
|
case 4: return *t;
|
||||||
|
default: return *x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -268,4 +270,7 @@ using TensorFuncExpr = EvalMultiFunction<TensorFunc,Tensor,Real>;
|
||||||
//! Symmetric tensor-valued function expression
|
//! Symmetric tensor-valued function expression
|
||||||
using STensorFuncExpr = EvalMultiFunction<STensorFunc,SymmTensor,Real>;
|
using STensorFuncExpr = EvalMultiFunction<STensorFunc,SymmTensor,Real>;
|
||||||
|
|
||||||
|
//! \brief Explicit instantiation of error flag.
|
||||||
|
template<> int EvalFunc::numError;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -717,7 +717,7 @@ static const ScalarFunc* parseFunction (const char* type, char* cline, Real C)
|
||||||
{
|
{
|
||||||
cline = strtok(cline,":");
|
cline = strtok(cline,":");
|
||||||
IFEM::cout << cline;
|
IFEM::cout << cline;
|
||||||
EvalFunc::numError = 0;
|
EvalFuncScalar<Real>::numError = 0;
|
||||||
ScalarFunc* sf = new EvalFunc(cline,"t",C);
|
ScalarFunc* sf = new EvalFunc(cline,"t",C);
|
||||||
if (EvalFunc::numError > 0)
|
if (EvalFunc::numError > 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#include "AnaSol.h"
|
#include "AnaSol.h"
|
||||||
#include "Function.h"
|
#include "Function.h"
|
||||||
|
#include "Tensor.h"
|
||||||
|
#include "TensorFunction.h"
|
||||||
#include "Vec3Oper.h"
|
#include "Vec3Oper.h"
|
||||||
#include "tinyxml.h"
|
#include "tinyxml.h"
|
||||||
|
|
||||||
|
@ -48,15 +50,15 @@ TEST(TestAnaSol, ParseDerivatives)
|
||||||
ASSERT_TRUE(v != nullptr);
|
ASSERT_TRUE(v != nullptr);
|
||||||
|
|
||||||
Vec3 X(1.0,2.0,3.0);
|
Vec3 X(1.0,2.0,3.0);
|
||||||
EXPECT_FLOAT_EQ((*v)(X),8.0);
|
EXPECT_DOUBLE_EQ((*v)(X),8.0);
|
||||||
EXPECT_FLOAT_EQ(v->deriv(X,1),3.0);
|
EXPECT_DOUBLE_EQ(v->deriv(X,1),3.0);
|
||||||
EXPECT_FLOAT_EQ(v->deriv(X,2),4.0);
|
EXPECT_DOUBLE_EQ(v->deriv(X,2),4.0);
|
||||||
EXPECT_FLOAT_EQ(v->deriv(X,3),1.0);
|
EXPECT_DOUBLE_EQ(v->deriv(X,3),1.0);
|
||||||
EXPECT_FLOAT_EQ(v->dderiv(X,1,1),6.0);
|
EXPECT_DOUBLE_EQ(v->dderiv(X,1,1),6.0);
|
||||||
EXPECT_FLOAT_EQ(v->dderiv(X,2,2),2.0);
|
EXPECT_DOUBLE_EQ(v->dderiv(X,2,2),2.0);
|
||||||
EXPECT_FLOAT_EQ(v->dderiv(X,3,3),0.0);
|
EXPECT_DOUBLE_EQ(v->dderiv(X,3,3),0.0);
|
||||||
EXPECT_FLOAT_EQ(v->dderiv(X,1,2),0.0);
|
EXPECT_DOUBLE_EQ(v->dderiv(X,1,2),0.0);
|
||||||
EXPECT_FLOAT_EQ(v->dderiv(X,3,2),0.0);
|
EXPECT_DOUBLE_EQ(v->dderiv(X,3,2),0.0);
|
||||||
|
|
||||||
VecFunc* v2 = mySol.getScalarSecSol();
|
VecFunc* v2 = mySol.getScalarSecSol();
|
||||||
ASSERT_TRUE(v2 != nullptr);
|
ASSERT_TRUE(v2 != nullptr);
|
||||||
|
@ -65,3 +67,124 @@ TEST(TestAnaSol, ParseDerivatives)
|
||||||
EXPECT_TRUE(v2->deriv(X,2) == Vec3(0.0,2.0,0.0));
|
EXPECT_TRUE(v2->deriv(X,2) == Vec3(0.0,2.0,0.0));
|
||||||
EXPECT_TRUE(v2->dderiv(X,1,1) == Vec3(6.0,0.0,0.0));
|
EXPECT_TRUE(v2->dderiv(X,1,1) == Vec3(6.0,0.0,0.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(TestAnaSol, ParseAD)
|
||||||
|
{
|
||||||
|
const char* input = "<anasol type=\"expression\" autodiff=\"true\">"
|
||||||
|
" <primary>"
|
||||||
|
" x^3+y^2+z"
|
||||||
|
" </primary>"
|
||||||
|
"</anasol>";
|
||||||
|
|
||||||
|
TiXmlDocument doc;
|
||||||
|
doc.Parse(input,nullptr,TIXML_ENCODING_UTF8);
|
||||||
|
const TiXmlElement* tag = doc.RootElement();
|
||||||
|
ASSERT_TRUE(tag != nullptr);
|
||||||
|
ASSERT_EQ(strcmp(tag->Value(),"anasol"),0);
|
||||||
|
|
||||||
|
AnaSol mySol(tag,true);
|
||||||
|
RealFunc* v = mySol.getScalarSol();
|
||||||
|
ASSERT_TRUE(v != nullptr);
|
||||||
|
|
||||||
|
mySol.setupSecondarySolutions();
|
||||||
|
|
||||||
|
Vec3 X(1.0,2.0,3.0);
|
||||||
|
const Vec3 grad1 = v->gradient(X);
|
||||||
|
const SymmTensor hess = v->hessian(X);
|
||||||
|
VecFunc* v2 = mySol.getScalarSecSol();
|
||||||
|
ASSERT_TRUE(v2 != nullptr);
|
||||||
|
const Vec3 grad2 = (*v2)(X);
|
||||||
|
EXPECT_DOUBLE_EQ((*v)(X),8.0);
|
||||||
|
EXPECT_DOUBLE_EQ(v->deriv(X,1),3.0);
|
||||||
|
EXPECT_DOUBLE_EQ(grad1[0],3.0);
|
||||||
|
EXPECT_DOUBLE_EQ(grad2[0],3.0);
|
||||||
|
EXPECT_DOUBLE_EQ(v->deriv(X,2),4.0);
|
||||||
|
EXPECT_DOUBLE_EQ(grad1[1],4.0);
|
||||||
|
EXPECT_DOUBLE_EQ(grad2[1],4.0);
|
||||||
|
EXPECT_DOUBLE_EQ(v->deriv(X,3),1.0);
|
||||||
|
EXPECT_DOUBLE_EQ(grad1[2],1.0);
|
||||||
|
EXPECT_DOUBLE_EQ(grad2[2],1.0);
|
||||||
|
|
||||||
|
EXPECT_DOUBLE_EQ(v->dderiv(X,1,1),6.0);
|
||||||
|
EXPECT_DOUBLE_EQ(hess(1,1), 6.0);
|
||||||
|
EXPECT_DOUBLE_EQ(v->dderiv(X,2,2),2.0);
|
||||||
|
EXPECT_DOUBLE_EQ(hess(2,2), 2.0);
|
||||||
|
EXPECT_DOUBLE_EQ(v->dderiv(X,3,3),0.0);
|
||||||
|
EXPECT_DOUBLE_EQ(hess(3,3), 0.0);
|
||||||
|
EXPECT_DOUBLE_EQ(v->dderiv(X,1,2),0.0);
|
||||||
|
EXPECT_DOUBLE_EQ(hess(1,2), 0.0);
|
||||||
|
EXPECT_DOUBLE_EQ(v->dderiv(X,3,2),0.0);
|
||||||
|
EXPECT_DOUBLE_EQ(hess(3,2), 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(TestAnaSol, ParseFD)
|
||||||
|
{
|
||||||
|
const char* input = "<anasol type=\"expression\">"
|
||||||
|
" <primary>"
|
||||||
|
" x^3+y^2+z"
|
||||||
|
" </primary>"
|
||||||
|
"</anasol>";
|
||||||
|
|
||||||
|
TiXmlDocument doc;
|
||||||
|
doc.Parse(input,nullptr,TIXML_ENCODING_UTF8);
|
||||||
|
const TiXmlElement* tag = doc.RootElement();
|
||||||
|
ASSERT_TRUE(tag != nullptr);
|
||||||
|
ASSERT_EQ(strcmp(tag->Value(),"anasol"),0);
|
||||||
|
|
||||||
|
AnaSol mySol(tag,true);
|
||||||
|
RealFunc* v = mySol.getScalarSol();
|
||||||
|
ASSERT_TRUE(v != nullptr);
|
||||||
|
|
||||||
|
mySol.setupSecondarySolutions();
|
||||||
|
|
||||||
|
Vec3 X(1.0,2.0,3.0);
|
||||||
|
const Vec3 grad1 = v->gradient(X);
|
||||||
|
VecFunc* v2 = mySol.getScalarSecSol();
|
||||||
|
ASSERT_TRUE(v2 != nullptr);
|
||||||
|
const Vec3 grad2 = (*v2)(X);
|
||||||
|
EXPECT_DOUBLE_EQ((*v)(X),8.0);
|
||||||
|
EXPECT_NEAR(v->deriv(X,1),3.0,1e-6);
|
||||||
|
EXPECT_NEAR(grad1[0],3.0,1e-6);
|
||||||
|
EXPECT_NEAR(grad2[0],3.0,1e-6);
|
||||||
|
EXPECT_NEAR(v->deriv(X,2),4.0,1e-6);
|
||||||
|
EXPECT_NEAR(grad1[1],4.0,1e-6);
|
||||||
|
EXPECT_NEAR(grad2[1],4.0,1e-6);
|
||||||
|
EXPECT_NEAR(v->deriv(X,3),1.0,1e-6);
|
||||||
|
EXPECT_NEAR(grad1[2],1.0,1e-6);
|
||||||
|
EXPECT_NEAR(grad2[2],1.0,1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(TestAnaSol, ParseADStress)
|
||||||
|
{
|
||||||
|
const char* input = "<anasol type=\"expression\" symmetric=\"true\" autodiff=\"true\">"
|
||||||
|
" <primary>"
|
||||||
|
" x^3+y^2+z | x^2+y^3+z"
|
||||||
|
" </primary>"
|
||||||
|
"</anasol>";
|
||||||
|
|
||||||
|
TiXmlDocument doc;
|
||||||
|
doc.Parse(input,nullptr,TIXML_ENCODING_UTF8);
|
||||||
|
const TiXmlElement* tag = doc.RootElement();
|
||||||
|
ASSERT_TRUE(tag != nullptr);
|
||||||
|
ASSERT_EQ(strcmp(tag->Value(),"anasol"),0);
|
||||||
|
|
||||||
|
AnaSol mySol(tag,false);
|
||||||
|
ASSERT_TRUE(mySol.getScalarSol() == nullptr);
|
||||||
|
ASSERT_TRUE(mySol.getVectorSol() != nullptr);
|
||||||
|
|
||||||
|
mySol.setupSecondarySolutions();
|
||||||
|
|
||||||
|
ASSERT_TRUE(mySol.getVectorSecSol() == nullptr);
|
||||||
|
const STensorFunc* v = mySol.getStressSol();
|
||||||
|
ASSERT_TRUE(v != nullptr);
|
||||||
|
|
||||||
|
Vec3 X(1.0,2.0,3.0);
|
||||||
|
const SymmTensor grad1 = (*v)(X);
|
||||||
|
EXPECT_DOUBLE_EQ(grad1(1,1), 3*X.x*X.x);
|
||||||
|
EXPECT_DOUBLE_EQ(grad1(1,2), 2*X.y);
|
||||||
|
EXPECT_DOUBLE_EQ(grad1(2,1), 2*X.y);
|
||||||
|
EXPECT_DOUBLE_EQ(grad1(2,2), 3*X.y*X.y);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user