Smith  0.1
Smith is an implicit thermal structural mechanics simulation code.
field_state.cpp
1 // Copyright (c) Lawrence Livermore National Security, LLC and
2 // other Smith Project Developers. See the top-level LICENSE file for
3 // details.
4 //
5 // SPDX-License-Identifier: (BSD-3-Clause)
6 
8 
9 namespace smith {
10 
12 {
13  return gretl::clone_state(
14  [](FEFieldPtr s) {
15  auto next = std::make_shared<FiniteElementState>(s->space(), s->name() + "_squared");
16  *next = *s;
17  *next *= *s;
18  return next;
19  },
20  [](const FEFieldPtr& s, const FEFieldPtr& /*next*/, FEDualPtr& s_, const FEDualPtr& next_) {
21  int sz = s->Size();
22  for (int i = 0; i < sz; ++i) {
23  (*s_)[i] += 2.0 * (*s)[i] * (*next_)[i];
24  }
25  },
26  state);
27 }
28 
29 gretl::State<double> innerProduct(const FieldState& a, const FieldState& b)
30 {
31  return gretl::create_state<double, double>(
32  gretl::defaultInitializeZeroDual<double, double>(),
33  [](FEFieldPtr A, FEFieldPtr B) { return smith::innerProduct(*A, *B); },
34  [](FEFieldPtr A, FEFieldPtr B, double, FEDualPtr& A_, FEDualPtr& B_, double product_) {
35  A_->Add(product_, *B);
36  B_->Add(product_, *A);
37  },
38  a, b);
39 }
40 
41 gretl::State<double> innerProduct(const ReactionState& a, const ReactionState& b)
42 {
43  return gretl::create_state<double, double>(
44  gretl::defaultInitializeZeroDual<double, double>(),
45  [](FEDualPtr A, FEDualPtr B) { return smith::innerProduct(*A, *B); },
46  [](FEDualPtr A, FEDualPtr B, double, FEFieldPtr& A_, FEFieldPtr& B_, double product_) {
47  A_->Add(product_, *B);
48  B_->Add(product_, *A);
49  },
50  a, b);
51 }
52 
53 FieldState axpby(double a, const FieldState& x, double b, const FieldState& y)
54 {
55  auto z = x.clone({x, y});
56 
57  z.set_eval([a, b](const gretl::UpstreamStates& upstreams, gretl::DownstreamState& downstream) {
58  const FEFieldPtr& X = upstreams[0].get<FEFieldPtr>();
59  const FEFieldPtr& Y = upstreams[1].get<FEFieldPtr>();
60  FEFieldPtr Z = std::make_shared<FiniteElementState>(X->space(), "axpby");
61  add(a, *X, b, *Y, *Z);
62  downstream.set<FEFieldPtr, FEDualPtr>(Z);
63  });
64 
65  z.set_vjp([a, b](gretl::UpstreamStates& upstreams, const gretl::DownstreamState& downstream) {
66  const FEDualPtr& Z_dual = downstream.get_dual<FEDualPtr, FEFieldPtr>();
67  FEDualPtr& X_dual = upstreams[0].get_dual<FEDualPtr, FEFieldPtr>();
68  FEDualPtr& Y_dual = upstreams[1].get_dual<FEDualPtr, FEFieldPtr>();
69  add(*X_dual, a, *Z_dual, *X_dual);
70  add(*Y_dual, b, *Z_dual, *Y_dual);
71  });
72 
73  return z.finalize();
74 }
75 
77 {
78  return gretl::clone_state(
79  [](const FEFieldPtr& X) { return std::make_shared<FiniteElementState>(X->space(), "zero"); },
80  [](const FEFieldPtr&, const FEFieldPtr&, FEDualPtr&, const FEDualPtr&) {}, x);
81 }
82 
83 FieldState axpby(const gretl::State<double>& a, const FieldState& x, const gretl::State<double>& b, const FieldState& y)
84 {
85  return gretl::clone_state(
86  [](FEFieldPtr X, FEFieldPtr Y, double A, double B) {
87  FEFieldPtr Z = std::make_shared<FiniteElementState>(X->space(), "axpby");
88  add(A, *X, B, *Y, *Z);
89  return Z;
90  },
91  [](FEFieldPtr X, FEFieldPtr Y, double A, double B, FEFieldPtr /*Z*/, FEDualPtr& X_, FEDualPtr& Y_, double& A_,
92  double& B_, const FEDualPtr& Z_) {
93  add(*X_, A, *Z_, *X_);
94  add(*Y_, B, *Z_, *Y_);
95  A_ += smith::innerProduct(*Z_, *X);
96  B_ += smith::innerProduct(*Z_, *Y);
97  },
98  x, y, a, b);
99 }
100 
104 FieldState weighted_sum(const std::vector<double>& weights, const std::vector<FieldState>& weighted_fields,
105  const std::vector<gretl::State<double>>& differentiable_weights,
106  const std::vector<FieldState>& differentiably_weighted_fields,
107  const std::vector<double>& differentiable_scale_factors)
108 {
109  SLIC_ERROR_IF(weights.size() != weighted_fields.size(),
110  "weights and the fields they are weighting do not match in size");
111  SLIC_ERROR_IF(differentiable_weights.size() != differentiably_weighted_fields.size(),
112  "differentiable weights and the fields they are weighting do not match in size");
113  SLIC_ERROR_IF(differentiable_weights.size() != differentiable_scale_factors.size(),
114  "differentiable weights and the vector of fixed scale factors do not match in size");
115  SLIC_ERROR_IF((weights.size() == 0) && (differentiable_weights.size() == 0),
116  "At least 1 weight must be passed to a weighted sum");
117 
118  std::vector<gretl::StateBase> inputs;
119  inputs.insert(inputs.end(), weighted_fields.begin(), weighted_fields.end());
120  inputs.insert(inputs.end(), differentiable_weights.begin(), differentiable_weights.end());
121  inputs.insert(inputs.end(), differentiably_weighted_fields.begin(), differentiably_weighted_fields.end());
122 
123  auto x = weights.size() ? weighted_fields[0] : differentiably_weighted_fields[0];
124  auto z = x.clone(inputs);
125 
126  z.set_eval([weights, differentiable_scale_factors](const gretl::UpstreamStates& upstreams,
127  gretl::DownstreamState& downstream) {
128  size_t num_weights = weights.size();
129  size_t num_diffable_weights = (upstreams.size() - num_weights) / 2;
130 
131  auto X = weights.size() ? upstreams[0].get<FEFieldPtr>()
132  : upstreams[num_weights + num_diffable_weights].get<FEFieldPtr>();
133 
134  FEFieldPtr Z = std::make_shared<FiniteElementState>(X->space(), "weighted_sum");
135 
136  if (num_weights > 0) {
137  double weightOld = weights[0];
138  auto vecOld = upstreams[0].get<FEFieldPtr>();
139  if (num_weights == 1) {
140  Z->Set(weightOld, *vecOld);
141  }
142  for (size_t i = 1; i < num_weights; ++i) {
143  double weightNew = weights[i];
144  add(weightOld, *vecOld, weightNew, *upstreams[i].get<FEFieldPtr>(), *Z);
145  weightOld = 1.0;
146  vecOld = Z;
147  }
148  }
149 
150  if (num_diffable_weights > 0) {
151  size_t start_index = 0;
152  double weightOld = 1.0;
153  FEFieldPtr vecOld = Z;
154 
155  if (weights.size() == 0) {
156  start_index = 1;
157  double scale = differentiable_scale_factors[0];
158  weightOld = scale * upstreams[num_weights].get<double>();
159  vecOld = upstreams[num_weights + num_diffable_weights].get<FEFieldPtr>();
160  if (num_diffable_weights == 1) {
161  Z->Set(weightOld, *vecOld);
162  }
163  }
164 
165  for (size_t i = start_index; i < num_diffable_weights; ++i) {
166  double scale = differentiable_scale_factors[i];
167  double weightNew = scale * upstreams[num_weights + i].get<double>();
168  add(weightOld, *vecOld, weightNew, *upstreams[num_weights + num_diffable_weights + i].get<FEFieldPtr>(), *Z);
169  weightOld = 1.0;
170  vecOld = Z;
171  }
172  }
173 
174  downstream.set<FEFieldPtr, FEDualPtr>(Z);
175  });
176 
177  z.set_vjp([weights, differentiable_scale_factors](gretl::UpstreamStates& upstreams,
178  const gretl::DownstreamState& downstream) {
179  size_t num_weights = weights.size();
180  size_t num_diffable_weights = (upstreams.size() - num_weights) / 2;
181 
182  const FEDualPtr& Z_dual = downstream.get_dual<FEDualPtr, FEFieldPtr>();
183 
184  for (size_t i = 0; i < num_weights; ++i) {
185  FEDualPtr& V_dual = upstreams[i].get_dual<FEDualPtr, FEFieldPtr>();
186  double weight = weights[i];
187  add(*V_dual, weight, *Z_dual, *V_dual);
188  }
189 
190  for (size_t i = 0; i < num_diffable_weights; ++i) {
191  double& weight_dual = upstreams[num_weights + i].get_dual<double, double>();
192  FEDualPtr& V_dual = upstreams[num_weights + num_diffable_weights + i].get_dual<FEDualPtr, FEFieldPtr>();
193  double scale = differentiable_scale_factors[i];
194  double weight = scale * upstreams[num_weights + i].get<double>();
195  FEFieldPtr V = upstreams[num_weights + num_diffable_weights + i].get<FEFieldPtr>();
196  add(*V_dual, weight, *Z_dual, *V_dual);
197  weight_dual += scale * smith::innerProduct(*Z_dual, *V);
198  }
199  });
200 
201  return z.finalize();
202 }
203 
205 {
206  weights_.insert(weights_.end(), b.weights_.begin(), b.weights_.end());
207  weighted_fields_.insert(weighted_fields_.end(), b.weighted_fields_.begin(), b.weighted_fields_.end());
209  b.differentiable_weights_.end());
215  return *this;
216 }
217 
219 {
220  const size_t num_initial_weights = weights_.size();
221 
222  weights_.insert(weights_.end(), b.weights_.begin(), b.weights_.end());
223  for (size_t n = num_initial_weights; n < weights_.size(); ++n) {
224  weights_[n] *= -1.0;
225  }
226 
227  weighted_fields_.insert(weighted_fields_.end(), b.weighted_fields_.begin(), b.weighted_fields_.end());
228 
230  b.differentiable_weights_.end());
231 
235 
236  const size_t num_initial_differentiable_weights = differentiable_scale_factors_.size();
237 
240  for (size_t n = num_initial_differentiable_weights; n < differentiable_scale_factors_.size(); ++n) {
242  }
243  return *this;
244 }
245 
247 {
248  FieldStateWeightedSum zero(std::vector<double>{}, std::vector<FieldState>{});
249  return zero -= *this;
250 }
251 
252 FieldStateWeightedSum::operator FieldState() const
253 {
254  return weighted_sum(weights_, weighted_fields_, differentiable_weights_, differentiably_weighted_fields_,
255  differentiable_scale_factors_);
256 }
257 
259 {
260  for (auto& w : weights_) {
261  w *= weight;
262  }
263  for (auto& w : differentiable_scale_factors_) {
264  w *= weight;
265  }
266  return *this;
267 }
268 
269 FieldStateWeightedSum operator*(double a, const FieldState& b) { return FieldStateWeightedSum({a}, {b}); }
270 
271 FieldStateWeightedSum operator*(const FieldState& b, double a) { return a * b; }
272 
274 {
275  FieldStateWeightedSum z = b;
276  return z *= a;
277 }
278 
280 {
281  FieldStateWeightedSum z = b;
282  return z *= a;
283 }
284 
285 FieldStateWeightedSum operator*(const gretl::State<double>& a, const FieldState& b)
286 {
287  return FieldStateWeightedSum({a}, {b}, 1.0);
288 }
289 
290 FieldStateWeightedSum operator*(const FieldState& b, const gretl::State<double>& a) { return a * b; }
291 
293 {
294  return FieldStateWeightedSum({1.0, 1.0}, {x, y});
295 }
296 
298 {
299  return FieldStateWeightedSum({1.0, -1.0}, {x, y});
300 }
301 
303 {
304  FieldStateWeightedSum c = ax;
305  return c += by;
306 }
307 
309 {
310  FieldStateWeightedSum c = ax;
311  return c -= by;
312 }
313 
315 {
316  FieldStateWeightedSum y1({1.0}, {y});
317  return ax + y1;
318 }
319 
320 FieldStateWeightedSum operator+(const FieldState& y, const FieldStateWeightedSum& ax) { return ax + y; }
321 
323 {
324  FieldStateWeightedSum z = ax;
325  return z += FieldStateWeightedSum({-1.0}, {y});
326 }
327 
329 {
330  FieldStateWeightedSum z = -by;
331  return z += FieldStateWeightedSum({1.0}, {x});
332 }
333 
334 } // namespace smith
Accelerator functionality.
Definition: smith.cpp:36
gretl::State< FEDualPtr, FEFieldPtr > ReactionState
typedef
Definition: field_state.hpp:23
std::shared_ptr< FiniteElementState > FEFieldPtr
typedef
Definition: field_state.hpp:20
FieldStateWeightedSum operator+(const FieldState &x, const FieldState &y)
add two FieldState
gretl::State< FEFieldPtr, FEDualPtr > FieldState
typedef
Definition: field_state.hpp:22
FieldState axpby(double a, const FieldState &x, double b, const FieldState &y)
gretl-function to compute a*x + b*y
Definition: field_state.cpp:53
std::shared_ptr< FiniteElementDual > FEDualPtr
typedef
Definition: field_state.hpp:21
FieldState square(const FieldState &state)
gretl-function to square (x^2) every component of the Field
Definition: field_state.cpp:11
gretl::State< double > innerProduct(const FieldState &a, const FieldState &b)
gretl-function to compute the inner product (vector l2-norm) of a and b
Definition: field_state.cpp:29
FieldStateWeightedSum operator*(double a, const FieldState &b)
multiply scalar by a FieldState to get a temporary FieldStateWeightedSum which can cast back to a Fie...
FieldState zeroCopy(const FieldState &x)
gretl-function to make a deep-copy of a FieldState and initialize it to 0.
Definition: field_state.cpp:76
FieldStateWeightedSum operator-(const FieldState &x, const FieldState &y)
subtract two FieldState
FieldState weighted_sum(const std::vector< double > &weights, const std::vector< FieldState > &weighted_fields, const std::vector< gretl::State< double >> &differentiable_weights, const std::vector< FieldState > &differentiably_weighted_fields, const std::vector< double > &differentiable_scale_factors)
compute the differentiable weighted sum of fields, weighted by both double weights,...
temporary object to register the multiplication of a gretl::State<double> with a FieldState....
FieldStateWeightedSum operator-() const
negate
FieldStateWeightedSum & operator*=(double weight)
mulitply by a fixed scalar
std::vector< double > weights_
non-differentiable weights
FieldStateWeightedSum & operator+=(const FieldStateWeightedSum &b)
add another weighted sum in place
std::vector< FieldState > weighted_fields_
fields to weight by non-differentiable weights
std::vector< double > differentiable_scale_factors_
flag differentiable weights to be negated
std::vector< FieldState > differentiably_weighted_fields_
fields to weight by differentiable weights
FieldStateWeightedSum & operator-=(const FieldStateWeightedSum &b)
subtract another weighted sum in place
std::vector< gretl::State< double > > differentiable_weights_
differentiable weights
A sentinel struct for eliding no-op tensor operations.
Definition: tensor.hpp:122