Hermes2D  2.0
weakforms_neutronics.cpp
1 // This file is part of Hermes2D.
2 //
3 // Hermes2D is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // Hermes2D is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Hermes2D. If not, see <http://www.gnu.org/licenses/>.
15 
16 #include "weakforms_neutronics.h"
17 
18 #include <algorithm>
19 #include <iomanip>
20 namespace Hermes
21 {
22  namespace Hermes2D
23  {
24  namespace WeakFormsNeutronics
25  {
26  namespace Monoenergetic
27  {
28  namespace Diffusion
29  {
30  template<typename Scalar>
31  DefaultWeakFormFixedSource<Scalar>::DefaultWeakFormFixedSource( Hermes::vector<std::string> regions,
32  Hermes::vector<double> D_map,
33  Hermes::vector<double> Sigma_a_map,
34  Hermes::vector<double> Q_map ) : WeakForm<Scalar>(1)
35  {
36  using namespace WeakFormsH1;
37 
38  for (unsigned int i = 0; i < regions.size(); i++)
39  {
40  /* Jacobian */
41  // Diffusion.
42  this->add_matrix_form(new DefaultJacobianDiffusion<Scalar>(0, 0, regions[i], new Hermes1DFunction<Scalar>(D_map[i]),
43  HERMES_SYM));
44  // Absorption.
45  this->add_matrix_form(new DefaultMatrixFormVol<Scalar>(0, 0, regions[i], new Hermes2DFunction<Scalar>(Sigma_a_map[i]),
46  HERMES_SYM));
47 
48  /* Residual */
49  // Diffusion.
50  this->add_vector_form(new DefaultResidualDiffusion<Scalar>(0, regions[i], new Hermes1DFunction<Scalar>(D_map[i])));
51  // Absorption.
52  this->add_vector_form(new DefaultResidualVol<Scalar>(0, regions[i], new Hermes2DFunction<Scalar>(Sigma_a_map[i])));
53  // Sources.
54  this->add_vector_form(new DefaultVectorFormVol<Scalar>(0, regions[i], new Hermes2DFunction<Scalar>(-Q_map[i])));
55  }
56  }
57  }
58  }
59 
60  namespace Multigroup
61  {
62  namespace MaterialProperties
63  {
64  namespace Common
65  {
66  void MaterialPropertyMaps::extend_to_multigroup(const MaterialPropertyMap0& mrsg_map,
67  MaterialPropertyMap1 *mrmg_map)
68  {
69  if(G == 1)
70  this->warn(W_MG_EXTENSION);
71 
72  MaterialPropertyMap0::const_iterator it;
73  for (it = mrsg_map.begin(); it != mrsg_map.end(); ++it)
74  (*mrmg_map)[it->first].assign(G, it->second);
75  }
76 
77  void MaterialPropertyMaps::extend_to_multiregion(const rank1& srmg_array,
78  MaterialPropertyMap1 *mrmg_map)
79  {
80  if(materials_list.empty())
81  throw Hermes::Exceptions::Exception(E_MR_EXTENSION);
82 
83  std::set<std::string>::const_iterator it;
84  for (it = materials_list.begin(); it != materials_list.end(); ++it)
85  (*mrmg_map)[*it] = srmg_array;
86  }
87 
88  void MaterialPropertyMaps::extend_to_multiregion_multigroup(const rank0& srsg_value,
89  MaterialPropertyMap1 *mrmg_map)
90  {
91  if(materials_list.empty())
92  throw Hermes::Exceptions::Exception(E_MR_EXTENSION);
93  if(G == 1)
94  this->warn(W_MG_EXTENSION);
95 
96  std::set<std::string>::const_iterator it;
97  for (it = materials_list.begin(); it != materials_list.end(); ++it)
98  (*mrmg_map)[*it].assign(G, srsg_value);
99  }
100 
101  void MaterialPropertyMaps::fill_with(double c, MaterialPropertyMap1 *mrmg_map)
102  {
103  if(materials_list.empty())
104  throw Hermes::Exceptions::Exception(E_MR_EXTENSION);
105 
106  std::set<std::string>::const_iterator it;
107  for (it = materials_list.begin(); it != materials_list.end(); ++it)
108  (*mrmg_map)[*it].assign(G, c);
109  }
110 
111  void MaterialPropertyMaps::validate()
112  {
113  using namespace ValidationFunctors;
114 
115  if(fission_multigroup_structure.empty())
116  fission_multigroup_structure = bool1(G, true);
117 
118  if(chi.empty())
119  {
120  fill_with(0.0, &chi);
121  MaterialPropertyMap1::iterator it = chi.begin();
122  for ( ; it != chi.end(); ++it)
123  it->second[0] = 1.0;
124  fission_multigroup_structure = bool1(G, false);
125  fission_multigroup_structure[0] = true;
126  }
127 
128  if(nu.empty() && !nuSigma_f.empty() && !Sigma_f.empty())
129  nu = NDArrayMapOp::divide<rank1>(nuSigma_f, Sigma_f);
130  else if(nuSigma_f.empty() && !nu.empty() && !Sigma_f.empty())
131  nuSigma_f = NDArrayMapOp::multiply<rank1>(nu, Sigma_f);
132  else if(Sigma_f.empty() && !nuSigma_f.empty() && !nu.empty())
133  Sigma_f = NDArrayMapOp::divide<rank1>(nuSigma_f, nu);
134  else if(!Sigma_f.empty() && !nuSigma_f.empty() && !nu.empty())
135  {
136  MaterialPropertyMap1 diff = NDArrayMapOp::subtract<rank1>(nuSigma_f,
137  NDArrayMapOp::multiply<rank1>(nu, Sigma_f) );
138  std::for_each(diff.begin(), diff.end(), ensure_trivial());
139  }
140  else
141  {
142  this->warn(W_NO_FISSION);
143  fill_with(0.0, &nu);
144  fill_with(0.0, &chi);
145  fill_with(0.0, &Sigma_f);
146  }
147 
148  if((nu.size() != Sigma_f.size()) || (nu.size() != chi.size()))
149  throw Hermes::Exceptions::Exception(E_NONMATCHING_PROPERTIES);
150 
151  if(Sigma_f.size() > 0)
152  {
153  std::for_each(nu.begin(), nu.end(), ensure_size(G));
154  std::for_each(Sigma_f.begin(), Sigma_f.end(), ensure_size(G));
155  std::for_each(chi.begin(), chi.end(), ensure_size(G));
156  }
157 
158  if(Sigma_a.size() > 0)
159  {
160  // Warn if \Sigma_a < \Sigma_f for any region (this indicates an unphysical situation, since
161  // by definition \Sigma_a = \Sigma_f + \Sigma_c + \Sigma_{n, p} + other possible reactions
162  // leading to neutron removal).
163  MaterialPropertyMap1::const_iterator ita = Sigma_a.begin();
164  MaterialPropertyMap1::const_iterator itf = Sigma_f.begin();
165  for ( ; ita != Sigma_a.end(); ++ita, ++itf)
166  {
167  rank1::const_iterator a = ita->second.begin();
168  rank1::const_iterator f = itf->second.begin();
169 
170  for ( ; a != ita->second.end(); ++a, ++f)
171  if(*a < *f)
172  this->warn(W_SA_LT_SF);
173  }
174  }
175  }
176 
177  const rank1& MaterialPropertyMaps::get_Sigma_f(std::string material) const
178  {
179  if(material == "-999") return this->Sigma_f.begin()->second;
180 
181  // Note that prop[e->elem_marker] cannot be used since 'prop' is a constant std::map for
182  // which operator[] is undefined.
183  MaterialPropertyMap1::const_iterator data = this->Sigma_f.find(material);
184  if(data != this->Sigma_f.end())
185  return data->second;
186  else
187  {
188  throw Hermes::Exceptions::Exception(E_INVALID_MARKER);
189  return *(new rank1()); // To avoid MSVC problems; execution should never come to this point.
190  }
191  }
192  const rank1& MaterialPropertyMaps::get_nu(std::string material) const
193  {
194  if(material == "-999") return this->nu.begin()->second;
195 
196  MaterialPropertyMap1::const_iterator data = this->nu.find(material);
197  if(data != this->nu.end())
198  return data->second;
199  else
200  {
201  throw Hermes::Exceptions::Exception(E_INVALID_MARKER);
202  return *(new rank1()); // To avoid MSVC problems; execution should never come to this point.
203  }
204  }
205  const rank1& MaterialPropertyMaps::get_chi(std::string material) const
206  {
207  if(material == "-999") return this->chi.begin()->second;
208 
209  MaterialPropertyMap1::const_iterator data = this->chi.find(material);
210  if(data != this->chi.end())
211  return data->second;
212  else
213  {
214  throw Hermes::Exceptions::Exception(E_INVALID_MARKER);
215  return *(new rank1()); // To avoid MSVC problems; execution should never come to this point.
216  }
217  }
218 
219  std::ostream & operator<< (std::ostream& os, const MaterialPropertyMaps& matprop)
220  {
221  using namespace std;
222 
223  os << std::endl;
224  os << setw(12) << "target group" << setw(10) << "chi" << setw(10) << "nu";
225  os << setw(10) << "Sigma_f" << std::endl;
226 
227  MaterialPropertyMap1::const_iterator data_elem = matprop.chi.begin();
228  for ( ; data_elem != matprop.chi.end(); ++data_elem)
229  {
230  string mat = data_elem->first;
231 
232  os << setw(80) << setfill('-') << ' ' << std::endl << setfill(' ');
233  os << setw(40) << mat << std::endl;
234  os << setw(80) << setfill('-') << ' ' << std::endl << setfill(' ');
235  for (unsigned int gto = 0; gto < matprop.G; gto++)
236  {
237  os << setw(6) << gto << setw(6) << ' ';
238  os << setw(10) << matprop.get_chi(mat)[gto];
239  os << setw(10) << matprop.get_nu(mat)[gto];
240  os << setw(10) << matprop.get_Sigma_f(mat)[gto];
241 
242  os << std::endl;
243  }
244  }
245 
246  os << std::endl;
247  return os;
248  }
249  }
250 
251  namespace Diffusion
252  {
253  MaterialPropertyMap1 MaterialPropertyMaps::extract_map2_diagonals(const MaterialPropertyMap2& map2)
254  {
255  MaterialPropertyMap1 diags;
256 
257  MaterialPropertyMap2::const_iterator map2_it = map2.begin();
258  for ( ; map2_it != map2.end(); ++map2_it)
259  {
260  diags[map2_it->first].reserve(G);
261  for (unsigned int g = 0; g < G; g++)
262  diags[map2_it->first].push_back(map2_it->second[g][g]);
263  }
264 
265  return diags;
266  }
267 
268  MaterialPropertyMap1 MaterialPropertyMaps::sum_map2_columns(const MaterialPropertyMap2& map2)
269  {
270  MaterialPropertyMap1 summed;
271 
272  MaterialPropertyMap2::const_iterator map2_it = map2.begin();
273  for ( ; map2_it != map2.end(); ++map2_it)
274  {
275  summed[map2_it->first].reserve(G);
276  for (unsigned int gfrom = 0; gfrom < G; gfrom++)
277  {
278  double sum = 0.0;
279 
280  for (unsigned int gto = 0; gto < G; gto++)
281  sum += map2_it->second[gto][gfrom];
282 
283  summed[map2_it->first].push_back(sum);
284  }
285  }
286 
287  return summed;
288  }
289 
290  MaterialPropertyMap2 MaterialPropertyMaps::create_map2_by_diagonals(const MaterialPropertyMap1& diags)
291  {
292  MaterialPropertyMap2 map2;
293 
294  MaterialPropertyMap1::const_iterator diags_it = diags.begin();
295  for ( ; diags_it != diags.end(); ++diags_it)
296  {
297  map2[diags_it->first].resize(G, rank1(G, 0.0));
298 
299  for (unsigned int g = 0; g < G; g++)
300  map2[diags_it->first][g][g] = diags_it->second[g];
301  }
302 
303  return map2;
304  }
305 
306  void MaterialPropertyMaps::fill_with(double c, MaterialPropertyMap2 *mrmg_map)
307  {
308  std::set<std::string>::const_iterator it;
309  for (it = materials_list.begin(); it != materials_list.end(); ++it)
310  (*mrmg_map)[*it].assign(G, rank1(G, c));
311  }
312 
313  void MaterialPropertyMaps::validate()
314  {
315  Common::MaterialPropertyMaps::validate();
316 
317  bool D_given = !D.empty();
318  bool Sigma_r_given = !Sigma_r.empty();
319  bool Sigma_s_given = !Sigma_s.empty();
320  bool Sigma_t_given = !Sigma_t.empty();
321  bool Sigma_a_given = !Sigma_a.empty();
322  bool Sigma_f_given = !Sigma_f.empty();
323  bool src_given = !src.empty();
324 
325  if(!Sigma_r_given)
326  {
327  // If Sigma_r is not given, we can calculate it from Sigma_t and Sigma_s.
328 
329  if(Sigma_t_given)
330  {
331  if(!Sigma_s_given)
332  {
333  if(Sigma_a_given)
334  {
335  // If Sigma_s is not given, but Sigma_a is, we can calculate Sigma_s from Sigma_t and Sigma_a.
336  Sigma_s = create_map2_by_diagonals(Common::NDArrayMapOp::subtract<rank1>(Sigma_t, Sigma_a));
337  }
338  else
339  {
340  // If only Sigma_t is given, we assume that all reaction terms are included in Sigma_t; all
341  // other x-sections will be set to zero.
342  this->warn(W_NO_SCATTERING);
343  fill_with(0.0, &Sigma_s);
344  }
345 
346  Sigma_s_given = true;
347  }
348  }
349  else
350  {
351  // If Sigma_t is not given, but Sigma_a and Sigma_s are, we can obtain Sigma_t from the latter two.
352 
353  if(!Sigma_s_given)
354  {
355  this->warn(W_NO_SCATTERING);
356  fill_with(0.0, &Sigma_s);
357  Sigma_s_given = true;
358  }
359 
360  if(Sigma_a_given)
361  Sigma_t = Common::NDArrayMapOp::add<rank1>(Sigma_a, sum_map2_columns(Sigma_s));
362  else
363  {
364  // If neither Sigma_r, Sigma_t, Sigma_a are given, we may have a purely fissioning system.
365  if(Sigma_f_given)
366  Sigma_t = Sigma_f;
367  else
368  throw Hermes::Exceptions::Exception(E_INSUFFICIENT_DATA);
369  }
370 
371  Sigma_t_given = true;
372  }
373 
374  Sigma_r = Common::NDArrayMapOp::subtract<rank1>(Sigma_t, extract_map2_diagonals(Sigma_s));
375  Sigma_r_given = true;
376  }
377 
378  // Now, we surely have Sigma_r ...
379 
380  if(scattering_multigroup_structure.empty())
381  scattering_multigroup_structure = bool2(G, Hermes::vector<bool>(G, true));
382 
383  if(!Sigma_s_given)
384  {
385  // If Sigma_s is not given, but Sigma_t is, we can obtain the former from the latter and from Sigma_r.
386  // Note that the execution will come here only if the user entered Sigma_r himself - otherwise, Sigma_s
387  // has been already set in the previous test case.
388 
389  if(Sigma_t_given)
390  {
391  Sigma_s = create_map2_by_diagonals(Common::NDArrayMapOp::subtract<rank1>(Sigma_t, Sigma_r));
392 
393  scattering_multigroup_structure = bool2(G, Hermes::vector<bool>(G, false));
394  for (unsigned int gto = 0; gto < G; gto++)
395  for (unsigned int gfrom = 0; gfrom < G; gfrom++)
396  if(gto == gfrom)
397  scattering_multigroup_structure[gto][gfrom] = true;
398  }
399  else
400  {
401  this->warn(W_NO_SCATTERING);
402  fill_with(0.0, &Sigma_s);
403  scattering_multigroup_structure = bool2(G, Hermes::vector<bool>(G, false));
404  }
405 
406  Sigma_s_given = true;
407  }
408 
409  // Now, we surely have Sigma_s and Sigma_r, one parameter to go ...
410 
411  if(!D_given)
412  {
413  MaterialPropertyMap1::const_iterator Sr_elem = Sigma_r.begin();
414  for ( ; Sr_elem != Sigma_r.end(); ++Sr_elem)
415  for (unsigned int g = 0; g < G; g++)
416  D[Sr_elem->first][g] = 1./(3.*Sr_elem->second[g]);
417 
418  D_given = true;
419  }
420 
421  if((D.size() != Sigma_r.size()) || (D.size() != Sigma_s.size()) || (src_given && D.size() != src.size()))
422  throw Hermes::Exceptions::Exception(E_NONMATCHING_PROPERTIES);
423 
424  using ValidationFunctors::ensure_size;
425  std::for_each(Sigma_s.begin(), Sigma_s.end(), ensure_size(G, G));
426  std::for_each(Sigma_r.begin(), Sigma_r.end(), ensure_size(G));
427  std::for_each(src.begin(), src.end(), ensure_size(G));
428  std::for_each(D.begin(), D.end(), ensure_size(G));
429  }
430 
431  const rank2& MaterialPropertyMaps::get_Sigma_s(std::string material) const
432  {
433  if(material == "-999") return this->Sigma_s.begin()->second;
434 
435  // Note that prop[e->elem_marker] cannot be used since 'prop' is a constant std::map for
436  // which operator[] is undefined.
437  MaterialPropertyMap2::const_iterator data = this->Sigma_s.find(material);
438  if(data != this->Sigma_s.end())
439  return data->second;
440  else
441  {
442  throw Hermes::Exceptions::Exception(E_INVALID_MARKER);
443  return *(new rank2()); // To avoid MSVC problems; execution should never come to this point.
444  }
445  }
446  const rank1& MaterialPropertyMaps::get_Sigma_r(std::string material) const
447  {
448  if(material == "-999") return this->Sigma_r.begin()->second;
449 
450  MaterialPropertyMap1::const_iterator data = this->Sigma_r.find(material);
451  if(data != this->Sigma_r.end())
452  return data->second;
453  else
454  {
455  throw Hermes::Exceptions::Exception(E_INVALID_MARKER);
456  return *(new rank1()); // To avoid MSVC problems; execution should never come to this point.
457  }
458  }
459  const rank1& MaterialPropertyMaps::get_D(std::string material) const
460  {
461  if(material == "-999") return this->D.begin()->second;
462 
463  MaterialPropertyMap1::const_iterator data = this->D.find(material);
464  if(data != this->D.end())
465  return data->second;
466  else
467  {
468  throw Hermes::Exceptions::Exception(E_INVALID_MARKER);
469  return *(new rank1()); // To avoid MSVC problems; execution should never come to this point.
470  }
471  }
472  const rank1& MaterialPropertyMaps::get_src(std::string material) const
473  {
474  if(material == "-999") return this->src.begin()->second;
475 
476  MaterialPropertyMap1::const_iterator data = this->src.find(material);
477  if(data != this->src.end())
478  return data->second;
479  else
480  {
481  throw Hermes::Exceptions::Exception(E_INVALID_MARKER);
482  return *(new rank1()); // To avoid MSVC problems; execution should never come to this point.
483  }
484  }
485 
486  HERMES_API std::ostream & operator<< (std::ostream& os, const MaterialPropertyMaps& matprop)
487  {
488  using namespace std;
489 
490  os << static_cast<const Common::MaterialPropertyMaps&>(matprop) << std::endl;
491 
492  os << setw(12) << "target group" << setw(10) << "D" << setw(10) << "Sigma_r";
493  os << setw(10) << "ext. src" << setw(22) << "Sigma_s" << std::endl;
494 
495  MaterialPropertyMap1::const_iterator data_elem = matprop.Sigma_r.begin();
496  for ( ; data_elem != matprop.Sigma_r.end(); ++data_elem)
497  {
498  string mat = data_elem->first;
499 
500  os << setw(80) << setfill('-') << ' ' << std::endl << setfill(' ');
501  os << setw(40) << mat << std::endl;
502  os << setw(80) << setfill('-') << ' ' << std::endl << setfill(' ');
503  for (unsigned int gto = 0; gto < matprop.G; gto++)
504  {
505  os << setw(6) << gto << setw(6) << ' ';
506  os << setw(10) << matprop.get_D(mat)[gto];
507  os << setw(10) << matprop.get_Sigma_r(mat)[gto];
508  os << setw(10);
509  if(matprop.src.empty())
510  os << "N/A";
511  else
512  os << matprop.get_src(mat)[gto];
513 
514  for (unsigned int gfrom = 0; gfrom < matprop.G; gfrom++)
515  os << setw(8) << matprop.get_Sigma_s(mat)[gto][gfrom];
516 
517  os << std::endl;
518  }
519  }
520 
521  return os << std::endl;
522  }
523  }
524  }
525 
526  namespace ElementaryForms
527  {
528  namespace Diffusion
529  {
530  template<typename ScalarClass>
531  template<typename Real, typename Scalar>
532  Scalar VacuumBoundaryCondition::Jacobian<ScalarClass>::matrix_form(int n, double *wt, Func<Scalar> *u_ext[], Func<Real> *u,
533  Func<Real> *v, Geom<Real> *e, Func<Scalar> **ext) const
534  {
535  Scalar result;
536 
537  if(geom_type == HERMES_PLANAR)
538  result = 0.5 * int_u_v<Real, Scalar>(n, wt, u, v);
539  else if(geom_type == HERMES_AXISYM_X)
540  result = 0.5 * int_y_u_v<Real, Scalar>(n, wt, u, v, e);
541  else
542  result = 0.5 * int_x_u_v<Real, Scalar>(n, wt, u, v, e);
543 
544  return result;
545  }
546 
547  template<typename ScalarClass>
548  template<typename Real, typename Scalar>
549  Scalar VacuumBoundaryCondition::Residual<ScalarClass>::vector_form(int n, double *wt, Func<Scalar> *u_ext[],
550  Func<Real> *v, Geom<Real> *e, Func<Scalar> **ext) const
551  {
552  Scalar result;
553 
554  if(geom_type == HERMES_PLANAR)
555  result = 0.5 * int_u_ext_v<Real, Scalar>(n, wt, u_ext[g], v);
556  else if(geom_type == HERMES_AXISYM_X)
557  result = 0.5 * int_y_u_ext_v<Real, Scalar>(n, wt, u_ext[g], v, e);
558  else
559  result = 0.5 * int_x_u_ext_v<Real, Scalar>(n, wt, u_ext[g], v, e);
560 
561  return result;
562  }
563 
564  template<typename ScalarClass>
565  template<typename Real, typename Scalar>
566  Scalar DiffusionReaction::Jacobian<ScalarClass>::matrix_form(int n, double *wt, Func<Scalar> *u_ext[], Func<Real> *u,
567  Func<Real> *v, Geom<Real> *e, Func<Scalar> **ext) const
568  {
569  Scalar result;
570 
571  std::string mat = this->mesh->get_element_markers_conversion().get_user_marker(e->elem_marker).marker;
572  rank1 D_elem = matprop.get_D(mat);
573  rank1 Sigma_r_elem = matprop.get_Sigma_r(mat);
574 
575  if(geom_type == HERMES_PLANAR)
576  {
577  result = D_elem[g] * int_grad_u_grad_v<Real, Scalar>(n, wt, u, v) +
578  Sigma_r_elem[g] * int_u_v<Real, Scalar>(n, wt, u, v);
579  }
580  else
581  {
582  if(geom_type == HERMES_AXISYM_X)
583  {
584  result = D_elem[g] * int_y_grad_u_grad_v<Real, Scalar>(n, wt, u, v, e) +
585  Sigma_r_elem[g] * int_y_u_v<Real, Scalar>(n, wt, u, v, e);
586  }
587  else
588  {
589  result = D_elem[g] * int_x_grad_u_grad_v<Real, Scalar>(n, wt, u, v, e) +
590  Sigma_r_elem[g] * int_x_u_v<Real, Scalar>(n, wt, u, v, e);
591  }
592  }
593  return result;
594  }
595 
596  template<typename ScalarClass>
597  template<typename Real, typename Scalar>
598  Scalar DiffusionReaction::Residual<ScalarClass>::vector_form(int n, double *wt, Func<Scalar> *u_ext[],
599  Func<Real> *v, Geom<Real> *e, Func<Scalar> **ext) const
600  {
601  Scalar result;
602 
603  std::string mat = this->mesh->get_element_markers_conversion().get_user_marker(e->elem_marker).marker;
604  rank1 D_elem = matprop.get_D(mat);
605  rank1 Sigma_r_elem = matprop.get_Sigma_r(mat);
606 
607  if(geom_type == HERMES_PLANAR)
608  {
609  result = D_elem[g] * int_grad_u_ext_grad_v<Real, Scalar>(n, wt, u_ext[g], v) +
610  Sigma_r_elem[g] * int_u_ext_v<Real, Scalar>(n, wt, u_ext[g], v);
611  }
612  else
613  {
614  if(geom_type == HERMES_AXISYM_X)
615  {
616  result = D_elem[g] * int_y_grad_u_ext_grad_v<Real, Scalar>(n, wt, u_ext[g], v, e) +
617  Sigma_r_elem[g] * int_y_u_ext_v<Real, Scalar>(n, wt, u_ext[g], v, e);
618  }
619  else
620  {
621  result = D_elem[g] * int_x_grad_u_ext_grad_v<Real, Scalar>(n, wt, u_ext[g], v, e) +
622  Sigma_r_elem[g] * int_x_u_ext_v<Real, Scalar>(n, wt, u_ext[g], v, e);
623  }
624  }
625  return result;
626  }
627 
628  template<typename ScalarClass>
629  template<typename Real, typename Scalar>
630  Scalar FissionYield::Jacobian<ScalarClass>::matrix_form( int n, double *wt, Func<Scalar> *u_ext[], Func<Real> *u,
631  Func<Real> *v, Geom<Real> *e, Func<Scalar> **ext) const
632  {
633  if(!matprop.get_fission_multigroup_structure()[gto])
634  return Scalar(0.0);
635 
636  Scalar result = Scalar(0);
637  if(geom_type == HERMES_PLANAR) result = int_u_v<Real, Scalar>(n, wt, u, v);
638  else
639  {
640  if(geom_type == HERMES_AXISYM_X) result = int_y_u_v<Real, Scalar>(n, wt, u, v, e);
641  else result = int_x_u_v<Real, Scalar>(n, wt, u, v, e);
642  }
643 
644  std::string mat = this->mesh->get_element_markers_conversion().get_user_marker(e->elem_marker).marker;
645  rank1 nu_elem = matprop.get_nu(mat);
646  rank1 Sigma_f_elem = matprop.get_Sigma_f(mat);
647  rank1 chi_elem = matprop.get_chi(mat);
648 
649  return result * chi_elem[gto] * nu_elem[gfrom] * Sigma_f_elem[gfrom];
650  }
651 
652  template<typename ScalarClass>
653  template<typename Real, typename Scalar>
654  Scalar FissionYield::OuterIterationForm<ScalarClass>::vector_form( int n, double *wt, Func<Scalar> *u_ext[],
655  Func<Real> *v, Geom<Real> *e, Func<Scalar> **ext) const
656  {
657  if(!matprop.get_fission_multigroup_structure()[g])
658  return Scalar(0.0);
659 
660  std::string mat = this->mesh->get_element_markers_conversion().get_user_marker(e->elem_marker).marker;
661  rank1 nu_elem = matprop.get_nu(mat);
662  rank1 Sigma_f_elem = matprop.get_Sigma_f(mat);
663  rank1 chi_elem = matprop.get_chi(mat);
664 
665  Scalar result = Scalar(0);
666  for (int i = 0; i < n; i++)
667  {
668  Scalar local_res = Scalar(0);
669  for (int gfrom = 0; gfrom < this->wf->get_ext().size(); gfrom++)
670  local_res += nu_elem[gfrom] * Sigma_f_elem[gfrom] * ext[gfrom]->val[i];
671 
672  local_res = local_res * wt[i] * v->val[i];
673 
674  if(geom_type == HERMES_AXISYM_X)
675  local_res = local_res * e->y[i];
676  else if(geom_type == HERMES_AXISYM_Y)
677  local_res = local_res * e->x[i];
678 
679  result += local_res;
680  }
681 
682  return result * chi_elem[g] / keff;
683  }
684 
685  template<typename ScalarClass>
686  template<typename Real, typename Scalar>
687  Scalar FissionYield::Residual<ScalarClass>::vector_form( int n, double *wt, Func<Scalar> *u_ext[],
688  Func<Real> *v, Geom<Real> *e, Func<Scalar> **ext ) const
689  {
690  if(!matprop.get_fission_multigroup_structure()[gto])
691  return Scalar(0.0);
692 
693  Scalar result = Scalar(0);
694  if(geom_type == HERMES_PLANAR) result = int_u_ext_v<Real, Scalar>(n, wt, u_ext[gfrom], v);
695  else
696  {
697  if(geom_type == HERMES_AXISYM_X) result = int_y_u_ext_v<Real, Scalar>(n, wt, u_ext[gfrom], v, e);
698  else result = int_x_u_ext_v<Real, Scalar>(n, wt, u_ext[gfrom], v, e);
699  }
700 
701  std::string mat = this->mesh->get_element_markers_conversion().get_user_marker(e->elem_marker).marker;
702  rank1 nu_elem = matprop.get_nu(mat);
703  rank1 Sigma_f_elem = matprop.get_Sigma_f(mat);
704  rank1 chi_elem = matprop.get_chi(mat);
705 
706  return result * chi_elem[gto] * nu_elem[gfrom] * Sigma_f_elem[gfrom];
707  }
708 
709  template<typename ScalarClass>
710  template<typename Real, typename Scalar>
711  Scalar Scattering::Jacobian<ScalarClass>::matrix_form( int n, double *wt, Func<Scalar> *u_ext[], Func<Real> *u,
712  Func<Real> *v, Geom<Real> *e, Func<Scalar> **ext ) const
713  {
714  Scalar result = Scalar(0);
715  if(geom_type == HERMES_PLANAR) result = int_u_v<Real, Scalar>(n, wt, u, v);
716  else
717  {
718  if(geom_type == HERMES_AXISYM_X) result = int_y_u_v<Real, Scalar>(n, wt, u, v, e);
719  else result = int_x_u_v<Real, Scalar>(n, wt, u, v, e);
720  }
721 
722  return result * matprop.get_Sigma_s(this->mesh->get_element_markers_conversion().get_user_marker(e->elem_marker).marker)[gto][gfrom];
723  }
724 
725  template<typename ScalarClass>
726  template<typename Real, typename Scalar>
727  Scalar Scattering::Residual<ScalarClass>::vector_form( int n, double *wt, Func<Scalar> *u_ext[],
728  Func<Real> *v, Geom<Real> *e, Func<Scalar> **ext ) const
729  {
730  Scalar result = Scalar(0);
731  if(geom_type == HERMES_PLANAR) result = int_u_ext_v<Real, Scalar>(n, wt, u_ext[gfrom], v);
732  else
733  {
734  if(geom_type == HERMES_AXISYM_X) result = int_y_u_ext_v<Real, Scalar>(n, wt, u_ext[gfrom], v, e);
735  else result = int_x_u_ext_v<Real, Scalar>(n, wt, u_ext[gfrom], v, e);
736  }
737 
738  return result * matprop.get_Sigma_s(this->mesh->get_element_markers_conversion().get_user_marker(e->elem_marker).marker)[gto][gfrom];
739  }
740 
741  template<typename ScalarClass>
742  template<typename Real, typename Scalar>
743  Scalar ExternalSources::LinearForm<ScalarClass>::vector_form(int n, double *wt, Func<Scalar> *u_ext[],
744  Func<Real> *v, Geom<Real> *e, Func<Scalar> **ext) const
745  {
746  std::string mat = this->mesh->get_element_markers_conversion().get_user_marker(e->elem_marker).marker;
747 
748  if(geom_type == HERMES_PLANAR)
749  return matprop.get_src(mat)[g] * int_v<Real>(n, wt, v);
750  else
751  {
752  if(geom_type == HERMES_AXISYM_X)
753  return matprop.get_src(mat)[g] * int_y_v<Real>(n, wt, v, e);
754  else
755  return matprop.get_src(mat)[g] * int_x_v<Real>(n, wt, v, e);
756  }
757  }
758  }
759  }
760 
761  namespace CompleteWeakForms
762  {
763  namespace Diffusion
764  {
765  template<typename Scalar>
766  void DefaultWeakFormFixedSource<Scalar>::lhs_init(unsigned int G, const MaterialPropertyMaps& matprop, Mesh *mesh,
767  GeomType geom_type)
768  {
769  bool2 Ss_nnz = matprop.get_scattering_multigroup_structure();
770  bool1 chi_nnz = matprop.get_fission_multigroup_structure();
771 
772  for (unsigned int gto = 0; gto < G; gto++)
773  {
774  this->add_matrix_form(new DiffusionReaction::Jacobian<Scalar>(gto, matprop, mesh, geom_type));
775  this->add_vector_form(new DiffusionReaction::Residual<Scalar>(gto, matprop, mesh, geom_type));
776 
777  for (unsigned int gfrom = 0; gfrom < G; gfrom++)
778  {
779  if(Ss_nnz[gto][gfrom])
780  {
781  this->add_matrix_form(new Scattering::Jacobian<Scalar>(gto, gfrom, matprop, mesh, geom_type));
782  this->add_vector_form(new Scattering::Residual<Scalar>(gto, gfrom, matprop, mesh, geom_type));
783  }
784 
785  if(chi_nnz[gto])
786  {
787  this->add_matrix_form(new FissionYield::Jacobian<Scalar>(gto, gfrom, matprop, mesh, geom_type));
788  this->add_vector_form(new FissionYield::Residual<Scalar>(gto, gfrom, matprop, mesh, geom_type));
789  }
790  }
791  }
792  }
793 
794  template<typename Scalar>
795  DefaultWeakFormFixedSource<Scalar>::DefaultWeakFormFixedSource(const MaterialPropertyMaps& matprop, Mesh *mesh,
796  GeomType geom_type) : WeakForm<Scalar>(matprop.get_G())
797  {
798  lhs_init(matprop.get_G(), matprop, mesh, geom_type);
799  for (unsigned int gto = 0; gto < matprop.get_G(); gto++)
800  this->add_vector_form(new ExternalSources::LinearForm<Scalar>(gto, matprop, mesh, geom_type));
801  }
802 
803  template<typename Scalar>
804  DefaultWeakFormFixedSource<Scalar>::DefaultWeakFormFixedSource( const MaterialPropertyMaps& matprop, Mesh *mesh,
805  Hermes2DFunction<Scalar>*f_src, std::string src_area,
806  GeomType geom_type ) : WeakForm<Scalar>(matprop.get_G())
807  {
808  lhs_init(matprop.get_G(), matprop, mesh, geom_type);
809  for (unsigned int gto = 0; gto < matprop.get_G(); gto++)
810  this->add_vector_form(new WeakFormsH1::DefaultVectorFormVol<Scalar>(gto, src_area, f_src, geom_type));
811  }
812 
813  template<typename Scalar>
814  DefaultWeakFormFixedSource<Scalar>::DefaultWeakFormFixedSource( const MaterialPropertyMaps& matprop, Mesh *mesh,
815  Hermes2DFunction<Scalar>*f_src,
816  Hermes::vector<std::string> src_areas,
817  GeomType geom_type ) : WeakForm<Scalar>(matprop.get_G())
818  {
819  lhs_init(matprop.get_G(), matprop, mesh, geom_type);
820  for (unsigned int gto = 0; gto < matprop.get_G(); gto++)
821  this->add_vector_form(new WeakFormsH1::DefaultVectorFormVol<Scalar>(gto, src_areas, f_src, geom_type));
822  }
823 
824  template<typename Scalar>
825  DefaultWeakFormFixedSource<Scalar>::DefaultWeakFormFixedSource( const MaterialPropertyMaps& matprop, Mesh *mesh,
826  const Hermes::vector<Hermes2DFunction<Scalar>*>& f_src,
827  std::string src_area,
828  GeomType geom_type ) : WeakForm<Scalar>(matprop.get_G())
829  {
830  if(f_src.size() != matprop.get_G())
831  throw Hermes::Exceptions::Exception(E_INVALID_SIZE);
832 
833  lhs_init(matprop.get_G(), matprop, mesh, geom_type);
834  for (unsigned int gto = 0; gto < matprop.get_G(); gto++)
835  this->add_vector_form(new WeakFormsH1::DefaultVectorFormVol<Scalar>(gto, src_area, f_src[gto], geom_type));
836  }
837 
838  template<typename Scalar>
839  DefaultWeakFormFixedSource<Scalar>::DefaultWeakFormFixedSource( const MaterialPropertyMaps& matprop, Mesh *mesh,
840  const Hermes::vector<Hermes2DFunction<Scalar>*>& f_src,
841  Hermes::vector<std::string> src_areas,
842  GeomType geom_type ) : WeakForm<Scalar>(matprop.get_G())
843  {
844  if(f_src.size() != matprop.get_G())
845  throw Hermes::Exceptions::Exception(E_INVALID_SIZE);
846 
847  lhs_init(matprop.get_G(), matprop, mesh, geom_type);
848  for (unsigned int gto = 0; gto < matprop.get_G(); gto++)
849  this->add_vector_form(new WeakFormsH1::DefaultVectorFormVol<Scalar>(gto, src_areas, f_src[gto], geom_type));
850  }
851 
852  template<typename Scalar>
853  DefaultWeakFormSourceIteration<Scalar>::DefaultWeakFormSourceIteration( const MaterialPropertyMaps& matprop, Mesh *mesh,
854  Hermes::vector<MeshFunction<Scalar>*>& iterates,
855  double initial_keff_guess,
856  GeomType geom_type ) : WeakForm<Scalar>(matprop.get_G())
857  {
858  bool2 Ss_nnz = matprop.get_scattering_multigroup_structure();
859 
860  for (unsigned int gto = 0; gto < matprop.get_G(); gto++)
861  {
862  this->add_matrix_form(new DiffusionReaction::Jacobian<Scalar>(gto, matprop, mesh, geom_type));
863  this->add_vector_form(new DiffusionReaction::Residual<Scalar>(gto, matprop, mesh, geom_type));
864 
865  for (unsigned int gfrom = 0; gfrom < matprop.get_G(); gfrom++)
866  {
867  if(Ss_nnz[gto][gfrom])
868  {
869  this->add_matrix_form(new Scattering::Jacobian<Scalar>(gto, gfrom, matprop, mesh, geom_type));
870  this->add_vector_form(new Scattering::Residual<Scalar>(gto, gfrom, matprop, mesh, geom_type));
871  }
872  }
873 
874  FissionYield::OuterIterationForm<Scalar>* keff_iteration_form =
875  new FissionYield::OuterIterationForm<Scalar>( gto, matprop, mesh, iterates, initial_keff_guess, geom_type );
876  keff_iteration_forms.push_back(keff_iteration_form);
877  this->add_vector_form(keff_iteration_form);
878  }
879  }
880 
881  template<typename Scalar>
882  void DefaultWeakFormSourceIteration<Scalar>::update_keff(double new_keff)
883  {
884  /* Somehow does not work with templates. A bug / typo from me?
885  Hermes::vector<FissionYield::OuterIterationForm<Scalar> *>::iterator it = keff_iteration_forms.begin();
886  for ( ; it != keff_iteration_forms.end(); ++it)
887  (*it)->update_keff(new_keff);
888  */
889  for(int i = 0; i < keff_iteration_forms.size(); i++)
890  keff_iteration_forms[i]->update_keff(new_keff);
891  }
892  }
893  }
894 
895  namespace SupportClasses
896  {
897  void SourceFilter::filter_fn(int n, Hermes::vector<double*> values, double* result)
898  {
899  for (int i = 0; i < n; i++)
900  {
901  result[i] = 0;
902  for (unsigned int j = 0; j < values.size(); j++)
903  result[i] += nu[j] * Sigma_f[j] * values.at(j)[i];
904  }
905  }
906  }
907  }
908  namespace Monoenergetic
909  {
910  namespace Diffusion
911  {
912  template class HERMES_API DefaultWeakFormFixedSource<double>;
913  template class HERMES_API DefaultWeakFormFixedSource<std::complex<double> >;
914  }
915  }
916  namespace Multigroup
917  {
918  namespace ElementaryForms
919  {
920  namespace Diffusion
921  {
922  template class HERMES_API FissionYield::Jacobian<double>;
923  template class HERMES_API FissionYield::Jacobian<std::complex<double> >;
924  template class HERMES_API FissionYield::OuterIterationForm<double>;
925  template class HERMES_API FissionYield::OuterIterationForm<std::complex<double> >;
926  template class HERMES_API FissionYield::Residual<double>;
927  template class HERMES_API FissionYield::Residual<std::complex<double> >;
928 
929  template class HERMES_API VacuumBoundaryCondition::Jacobian<double>;
930  template class HERMES_API VacuumBoundaryCondition::Jacobian<std::complex<double> >;
931  template class HERMES_API VacuumBoundaryCondition::Residual<double>;
932  template class HERMES_API VacuumBoundaryCondition::Residual<std::complex<double> >;
933 
934  template double VacuumBoundaryCondition::Jacobian<double>::matrix_form<double, double>(int n, double *wt, Func<double> *u_ext[], Func<double> *u,
935  Func<double> *v, Geom<double> *e, Func<double> **ext) const;
936 
937  template double VacuumBoundaryCondition::Residual<double>::vector_form<double, double>(int n, double *wt, Func<double> *u_ext[],
938  Func<double> *v, Geom<double> *e, Func<double> **ext) const;
939 
940  template double DiffusionReaction::Jacobian<double>::matrix_form<double, double>(int n, double *wt, Func<double> *u_ext[], Func<double> *u,
941  Func<double> *v, Geom<double> *e, Func<double> **ext) const;
942 
943  template double DiffusionReaction::Residual<double>::vector_form<double, double>(int n, double *wt, Func<double> *u_ext[],
944  Func<double> *v, Geom<double> *e, Func<double> **ext) const;
945 
946  template double FissionYield::Jacobian<double>::matrix_form<double, double>( int n, double *wt, Func<double> *u_ext[], Func<double> *u,
947  Func<double> *v, Geom<double> *e, Func<double> **ext) const;
948 
949  template double FissionYield::OuterIterationForm<double>::vector_form<double, double>( int n, double *wt, Func<double> *u_ext[],
950  Func<double> *v, Geom<double> *e, Func<double> **ext ) const;
951 
952  template double FissionYield::Residual<double>::vector_form<double, double>( int n, double *wt, Func<double> *u_ext[],
953  Func<double> *v, Geom<double> *e, Func<double> **ext ) const;
954 
955  template double Scattering::Jacobian<double>::matrix_form<double, double>( int n, double *wt, Func<double> *u_ext[], Func<double> *u,
956  Func<double> *v, Geom<double> *e, Func<double> **ext ) const;
957 
958  template double Scattering::Residual<double>::vector_form<double, double>( int n, double *wt, Func<double> *u_ext[],
959  Func<double> *v, Geom<double> *e, Func<double> **ext ) const;
960 
961  template double ExternalSources::LinearForm<double>::vector_form<double, double>(int n, double *wt, Func<double> *u_ext[],
962  Func<double> *v, Geom<double> *e, Func<double> **ext) const;
963  }
964  }
965 
966  namespace CompleteWeakForms
967  {
968  namespace Diffusion
969  {
970  template class HERMES_API DefaultWeakFormFixedSource<double>;
971  template class HERMES_API DefaultWeakFormFixedSource<std::complex<double> >;
972 
973  template class HERMES_API DefaultWeakFormSourceIteration<double>;
974  template class HERMES_API DefaultWeakFormSourceIteration<std::complex<double> >;
975  }
976  }
977  }
978  }
979  }
980 }