1 //                                               -*- C++ -*-
2 /**
3  * @brief Canonical tensor gradient
4  *
5  *  Copyright 2005-2021 Airbus-EDF-IMACS-ONERA-Phimeca
6  *
7  *  This library is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU Lesser General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License
18  *  along with this library.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include "openturns/CanonicalTensorGradient.hxx"
23 #include "openturns/PersistentObjectFactory.hxx"
24 #include "openturns/Log.hxx"
25 #include "openturns/Os.hxx"
26 
27 BEGIN_NAMESPACE_OPENTURNS
28 
29 
30 
31 CLASSNAMEINIT(CanonicalTensorGradient)
32 
33 static const Factory<CanonicalTensorGradient> Factory_CanonicalTensorGradient;
34 
35 /* Default constructor */
CanonicalTensorGradient()36 CanonicalTensorGradient::CanonicalTensorGradient()
37   : GradientImplementation()
38   , evaluation_()
39 {
40   // Nothing to do
41 }
42 
43 /* Default constructor */
CanonicalTensorGradient(const CanonicalTensorEvaluation & evaluation)44 CanonicalTensorGradient::CanonicalTensorGradient(const CanonicalTensorEvaluation & evaluation)
45   : GradientImplementation()
46   , evaluation_(evaluation)
47 {
48   // Nothing to do
49 }
50 
51 
52 /* Virtual constructor */
clone() const53 CanonicalTensorGradient * CanonicalTensorGradient::clone() const
54 {
55   return new CanonicalTensorGradient(*this);
56 }
57 
58 
59 /* Comparison operator */
operator ==(const CanonicalTensorGradient & other) const60 Bool CanonicalTensorGradient::operator ==(const CanonicalTensorGradient & other) const
61 {
62   return (evaluation_ == other.evaluation_);
63 }
64 
65 /* String converter */
__repr__() const66 String CanonicalTensorGradient::__repr__() const
67 {
68   OSS oss(true);
69   oss << "class=" << CanonicalTensorGradient::GetClassName()
70       << " name=" << getName()
71       << " evaluation=" << evaluation_;
72   return oss;
73 }
74 
75 /* String converter */
__str__(const String &) const76 String CanonicalTensorGradient::__str__(const String & ) const
77 {
78   return __repr__();
79 }
80 
81 
82 /* Gradient */
gradient(const Point & inP) const83 Matrix CanonicalTensorGradient::gradient(const Point & inP) const
84 {
85   const UnsignedInteger inputDimension = getInputDimension();
86   if (inP.getDimension() != inputDimension) throw InvalidArgumentException(HERE) << "Error: trying to evaluate a Function with an argument of invalid dimension";
87   const UnsignedInteger outputDimension = getOutputDimension();
88 
89   callsNumber_.increment();
90 
91   const UnsignedInteger m = evaluation_.getRank();
92   Point prodI(m, 1.0);
93 
94   Sample sumRI(m, inputDimension);
95   Sample sumdRI(m, inputDimension);
96 
97   for (UnsignedInteger j = 0; j < inputDimension; ++ j)
98   {
99     const Point xj(1, inP[j]);
100     const Collection<Function> basisI(evaluation_.getBasis(j));
101     const UnsignedInteger basisSize = evaluation_.getDegrees()[j];
102 
103     // compute phi_(i,j)(xj), phi_(i,j)'(xj)
104     Point phiXj(basisSize);
105     Point dphiXj(basisSize);
106     for (UnsignedInteger k = 0; k < basisSize; ++ k)
107     {
108       phiXj[k] = basisI[k](xj)[0];
109       dphiXj[k] = basisI[k].gradient(xj)(0, 0);
110     }
111 
112     for (UnsignedInteger i = 0; i < m; ++ i)
113     {
114       const Point coeffI(evaluation_.getCoefficients(i, j));
115       Scalar sumI = 0.0;
116       Scalar sumdI = 0.0;
117       for (UnsignedInteger k = 0; k < basisSize; ++ k)
118       {
119         if (coeffI[k] != 0.0)
120         {
121           sumI += coeffI[k] * phiXj[k];
122           sumdI += coeffI[k] * dphiXj[k];
123         }
124       }
125       sumRI(i, j) = sumI;
126       sumdRI(i, j) = sumdI;
127       prodI[i] *= sumI;
128     }
129   }
130 
131   Matrix out(inputDimension, outputDimension);
132   for (UnsignedInteger j = 0; j < inputDimension; ++ j)
133   {
134     Scalar dj = 0.0;
135     for (UnsignedInteger i = 0; i < m; ++ i)
136     {
137       dj += prodI[i] * (sumdRI(i, j) / sumRI(i, j));
138     }
139     out(j, 0) = dj;
140   }
141   return out;
142 }
143 
144 /* Accessor for input point dimension */
getInputDimension() const145 UnsignedInteger CanonicalTensorGradient::getInputDimension() const
146 {
147   return evaluation_.getInputDimension();
148 }
149 
150 /* Accessor for output point dimension */
getOutputDimension() const151 UnsignedInteger CanonicalTensorGradient::getOutputDimension() const
152 {
153   return evaluation_.getOutputDimension();
154 }
155 
156 /* Method save() stores the object through the StorageManager */
save(Advocate & adv) const157 void CanonicalTensorGradient::save(Advocate & adv) const
158 {
159   GradientImplementation::save(adv);
160   adv.saveAttribute("evaluation_", evaluation_);
161 }
162 
163 /* Method load() reloads the object from the StorageManager */
load(Advocate & adv)164 void CanonicalTensorGradient::load(Advocate & adv)
165 {
166   GradientImplementation::load(adv);
167   adv.loadAttribute("evaluation_", evaluation_);
168 }
169 
170 END_NAMESPACE_OPENTURNS
171