Line data Source code
1 : /**********************************************************************/
2 : /* DO NOT MODIFY THIS HEADER */
3 : /* MAGPIE - Mesoscale Atomistic Glue Program for Integrated Execution */
4 : /* */
5 : /* Copyright 2017 Battelle Energy Alliance, LLC */
6 : /* ALL RIGHTS RESERVED */
7 : /**********************************************************************/
8 : #ifdef GSL_ENABLED
9 :
10 : #include "PolyatomicDisplacementFunction.h"
11 :
12 : // mytrim includes
13 : #include <mytrim/simconf.h>
14 : #include <mytrim/ion.h>
15 : #include <mytrim/element.h>
16 :
17 : // general includes
18 : #include <assert.h>
19 : #include <limits>
20 : #include <exception>
21 :
22 : // gsl includes
23 : #include "gsl/gsl_sf_legendre.h"
24 : #include "gsl/gsl_integration.h"
25 :
26 38 : PolyatomicDisplacementFunction::PolyatomicDisplacementFunction(
27 : std::vector<MyTRIM_NS::Element> polyatomic_material,
28 : nrt_type damage_function_type,
29 38 : std::vector<std::vector<Real>> Ecap)
30 : : PolyatomicDisplacementFunctionBase(polyatomic_material, damage_function_type, Ecap),
31 76 : _total_displacement_function(_damage_function_type == TOTAL)
32 : {
33 38 : if (damage_function_type != TOTAL && damage_function_type != NET)
34 0 : throw std::exception();
35 :
36 : // set the number of indices
37 38 : _n_indices = 2;
38 :
39 : Real Edisp_min = std::numeric_limits<Real>::max();
40 99 : for (unsigned int j = 0; j < _n_species; ++j)
41 61 : if (_material->_element[j]._Edisp < Edisp_min)
42 : Edisp_min = _material->_element[j]._Edisp;
43 38 : _energy_history[0] = Edisp_min;
44 :
45 : // set initial conditions for _displacement_function,
46 : // note: for net displacement function, the gii = 1, for total displacement function nij = 0
47 38 : if (_damage_function_type == NET)
48 87 : for (unsigned int i = 0; i < _n_species; ++i)
49 53 : _displacement_function[0][mapIndex(i, i, 0)] = 1;
50 38 : }
51 :
52 : std::vector<Real>
53 71241 : PolyatomicDisplacementFunction::getRHS(Real energy)
54 : {
55 71241 : std::vector<Real> f(_problem_size);
56 185163 : for (unsigned int i = 0; i < nSpecies(); ++i)
57 : {
58 113922 : Real stopping_power = stoppingPower(i, energy);
59 199284 : for (unsigned int j = 0; j < nSpecies(); ++j)
60 : {
61 : // working on the right hand side for nu_ij
62 199284 : unsigned int n = mapIndex(i, j, 0);
63 199284 : f[n] = 0;
64 :
65 569292 : for (unsigned int k = 0; k < nSpecies(); ++k)
66 370008 : f[n] += numberFraction(k) *
67 370008 : (integralTypeI(energy, i, j, k) + integralTypeII(energy, i, j, k)) / stopping_power;
68 : }
69 : }
70 71241 : return f;
71 : }
72 :
73 : Real
74 505898 : PolyatomicDisplacementFunction::integralTypeI(Real energy,
75 : unsigned int i,
76 : unsigned int j,
77 : unsigned int k) const
78 : {
79 505898 : Real upper_integration_limit = energy * _lambda[i][k];
80 : Real integral = 0;
81 505898 : Real delta_kj = k == j && _total_displacement_function ? 1 : 0;
82 505898 : Real Ebind = _material->_element[k]._Elbind;
83 :
84 : // the integration follows the already existing energies
85 12023656 : for (unsigned int l = 1; l < _energy_history.size(); ++l)
86 : {
87 : // adjust integration limits to be within E_{l-1} ... min(E_l, upper_integration_limit)
88 11517758 : Real lower = _energy_history[l - 1];
89 11517758 : Real upper = std::min(_energy_history[l], upper_integration_limit);
90 :
91 : // nothing to integrate
92 11517758 : if (lower > upper)
93 2019173 : continue;
94 :
95 : // now integrate from lower to upper
96 9498585 : Real f = 0.5 * (upper - lower);
97 47492925 : for (unsigned int qp = 0; qp < _quad_order; ++qp)
98 : {
99 37994340 : Real recoil_energy = f * (_quad_points[qp] + 1) + lower;
100 37994340 : integral += f * _quad_weights[qp] * scatteringCrossSection(i, k, energy, recoil_energy) *
101 37994340 : displacementProbability(k, recoil_energy) *
102 37994340 : (delta_kj + linearInterpolation(recoil_energy - Ebind, k, j));
103 : }
104 : }
105 505898 : return integral;
106 : }
107 :
108 : Real
109 505898 : PolyatomicDisplacementFunction::integralTypeII(Real energy,
110 : unsigned int i,
111 : unsigned int j,
112 : unsigned int k) const
113 : {
114 505898 : Real upper_integration_limit = energy * _lambda[i][k];
115 505898 : Real threshold = std::min(_asymptotic_threshold, energy * _lambda[i][k]);
116 :
117 : // store the current displacement function value
118 505898 : Real current_value = linearInterpolation(energy, i, j);
119 :
120 : // estimate the derivative d(nu_i) / dE:
121 505898 : Real dE = _energy_history.back() - _energy_history[_energy_history.size() - 2];
122 505898 : Real derivative = (current_value - linearInterpolation(energy - dE, i, j)) / dE;
123 :
124 : // integrate up to threshold and multiply by estimate of the derivative
125 505898 : Real integral = -weightedScatteringIntegral(energy, threshold, i, k) * derivative;
126 :
127 505898 : if (energy * _lambda[i][k] <= _asymptotic_threshold)
128 : return integral;
129 :
130 : // the integration follows the already existing energies
131 12529554 : for (unsigned int l = 0; l < _energy_history.size(); ++l)
132 : {
133 : // adjust integration limits to be within
134 : Real lower;
135 12023656 : if (l == 0)
136 505898 : lower = _asymptotic_threshold;
137 : else
138 11517758 : lower = std::max(_energy_history[l - 1], _asymptotic_threshold);
139 :
140 12023656 : Real upper = std::min(_energy_history[l], upper_integration_limit);
141 :
142 : // nothing to integrate
143 12023656 : if (lower > upper)
144 2019173 : continue;
145 :
146 : // now integrate from lower to upper
147 10004483 : Real f = 0.5 * (upper - lower);
148 50022415 : for (unsigned int qp = 0; qp < _quad_order; ++qp)
149 : {
150 40017932 : Real recoil_energy = f * (_quad_points[qp] + 1) + lower;
151 40017932 : integral += f * _quad_weights[qp] * scatteringCrossSection(i, k, energy, recoil_energy) *
152 40017932 : (nonCaptureProbability(i, k, energy, recoil_energy) *
153 40017932 : linearInterpolation(energy - recoil_energy, i, j) -
154 : current_value);
155 : }
156 : }
157 : return integral;
158 : }
159 :
160 : #endif
|