Flow123d
linear_reaction.cc
Go to the documentation of this file.
1 #include <iostream>
2 #include <cstring>
3 #include <stdlib.h>
4 #include <math.h>
5 
6 #include "reaction/reaction.hh"
9 #include "system/system.hh"
10 #include "system/sys_profiler.hh"
11 
12 #include "la/distribution.hh"
13 #include "mesh/mesh.h"
14 
15 #define MOBILE 0
16 #define IMMOBILE 1
17 
18 
19 using namespace Input::Type;
20 
22  = Record("Substep", "Equation for reading information about radioactive decays.")
23  .declare_key("parent", String(), Default::obligatory(),
24  "Identifier of an isotope.")
25  .declare_key("half_life", Double(), Default::optional(),
26  "Half life of the parent substance.")
27  .declare_key("kinetic", Double(), Default::optional(),
28  "Kinetic constants describing first order reactions.")
29  .declare_key("products", Array(String()), Default::obligatory(),
30  "Identifies isotopes which decays parental atom to.")
31  .declare_key("branch_ratios", Array(Double()), Default("1.0"), // default is one product, with ratio == 1.0
32  "Decay chain branching percentage.");
33 
34 
36  = Record("LinearReactions", "Information for a decision about the way to simulate radioactive decay.")
39  "Description of particular decay chain substeps.");
40 
41 
42 using namespace std;
43 
45  : ReactionTerm(init_mesh, in_rec),
46  reaction_matrix(nullptr)
47 {
48 }
49 
51 {
53  if(prev_conc != nullptr){
54  delete[](prev_conc);
55  }
56 }
57 
59 {
60  ASSERT(distribution != nullptr, "Distribution has not been set yet.\n");
61  ASSERT(time_ != nullptr, "Time governor has not been set yet.\n");
62 
63  prev_conc = new double[ names_.size() ];
65 
68 }
69 
70 
71 double **Linear_reaction::allocate_reaction_matrix(void) //reaction matrix initialization
72 {
73  unsigned int rows, cols;
74 
75  DBGMSG("We are going to allocate reaction matrix\n");
76  if (reaction_matrix == nullptr) reaction_matrix = (double **)xmalloc(names_.size() * sizeof(double*));//allocation section
77  for(rows = 0; rows < names_.size(); rows++){
78  reaction_matrix[rows] = (double *)xmalloc(names_.size() * sizeof(double));
79  }
80  for(rows = 0; rows < names_.size();rows++){
81  for(cols = 0; cols < names_.size(); cols++){
82  if(rows == cols) reaction_matrix[rows][cols] = 1.0;
83  else reaction_matrix[rows][cols] = 0.0;
84  }
85  }
86 
87  //print_reaction_matrix();
88  return reaction_matrix;
89 }
90 
91 /*double **Linear_reaction::modify_reaction_matrix(Input::Record in_rec) //prepare the matrix, which describes reactions
92 {
93  int rows,cols, index_par, bif_id;
94  int *index_child;
95  double rel_step, prev_rel_step;
96 
97  half_lives = (double *)xmalloc(nr_of_decays * sizeof(double));
98  bifurcation.resize(nr_of_decays);
99 
100  if(reaction_matrix == NULL){
101  xprintf(Msg,"\nReaction matrix pointer is NULL.\n");
102  return NULL;
103  }
104 
105  set_indices(in_rec);
106  set_half_lives(in_rec);
107  set_bifurcation(in_rec);
108 
109  if(nr_of_decays > 0){
110  //pole rozpaduu
111  Input::Array decay_array = in_rec.val<Input::Array>("decays");
112  int dec_nr = -1;
113  //iterator do cyklu
114  for(Input::Iterator<Input::Record> dec_it = decay_array.begin<Input::Record>(); dec_it != decay_array.end(); ++dec_it, ++dec_nr)
115  {
116  index_par = substance_ids[dec_nr][0]; // pole indexu parentu, because indecees in input file run from one whereas indeces in C++ run from ZERO
117  //int first_index = substance_ids[0];
118 
119  if(cols < (nr_of_isotopes - 1)){
120  rel_step = time_step/half_lives[dec_nr];
121  }
122  reaction_matrix[index_par][index_par] = pow(0.5,rel_step);
123 
124  Input::Array prod_array = dec_it->val<Input::Array>("products");
125 
126  int i = 0;
127  for(Input::Iterator<Input::Array> prod_it = prod_array.begin<Input::Array>(); prod_it != prod_array.end(); ++prod_it, ++i)
128  {
129  //bif_id = cols;
130  reaction_matrix[index_par][substance_ids[dec_nr][i]] += (1 - pow(0.5,rel_step)) * bifurcation[dec_nr][substance_ids[dec_nr][i]];
131  }
132  }
133  }
134  print_reaction_matrix();//just for control print
135  return reaction_matrix;
136 }*/
137 
138 double **Linear_reaction::modify_reaction_matrix(void) //All the parameters are supposed to be known
139  {
140  unsigned int index_par;
141  double rel_step;
142 
143  if (reaction_matrix == nullptr) {
144  xprintf(Warn, "\nReaction matrix pointer is NULL.\n");
145  return nullptr;
146  }
147 
148  for (unsigned int i_decay = 0; i_decay < half_lives.size(); i_decay++) {
149  index_par = substance_ids[i_decay][0];
150  rel_step = time_->dt() / half_lives[i_decay];
151  reaction_matrix[index_par][index_par] = pow(0.5, rel_step);
152 
153  for (unsigned int i_product = 1; i_product < substance_ids[i_decay].size(); ++i_product)
154  reaction_matrix[index_par][ substance_ids[i_decay][i_product] ]
155  = (1 - pow(0.5, rel_step))* bifurcation[i_decay][i_product-1];
156  }
157  // print_reaction_matrix(); //just for control print
158  return reaction_matrix;
159 }
160 
161 double **Linear_reaction::compute_reaction(double **concentrations, int loc_el) //multiplication of concentrations array by reaction matrix
162 {
163  unsigned int cols, rows;
164 
165  if (reaction_matrix == nullptr) return concentrations;
166 
167  for(cols = 0; cols < names_.size(); cols++){
168  prev_conc[cols] = concentrations[cols][loc_el];
169  concentrations[cols][loc_el] = 0.0;
170  }
171 
172  for(rows = 0; rows < names_.size(); rows++){
173  for(cols = 0; cols < names_.size(); cols++){
174  concentrations[rows][loc_el] += prev_conc[cols] * reaction_matrix[cols][rows];
175  }
176  }
177 
178  return concentrations;
179 }
180 
181 
182 void Linear_reaction::print_half_lives(int nr_of_substances) {
183  int i;
184 
185  xprintf(Msg, "\nHalf-lives are defined as:");
186  for (i = 0; i < (nr_of_substances - 1); i++) {
187  if (i < (nr_of_substances - 2)) //cout << " " << half_lives[i] <<",";
188  xprintf(Msg, " %f", half_lives[i]);
189  if (i == (nr_of_substances - 2)) //cout << " " << half_lives[i] <<"\n";
190  xprintf(Msg, " %f\n", this->half_lives[i]);
191  }
192 }
193 
194 // TODO: check duplicity of parents
195 // raise warning if sum of ratios is not one
197 {
198  unsigned int idx;
199 
200  Input::Array decay_array = in_rec.val<Input::Array>("decays");
201 
202  substance_ids.resize( decay_array.size() );
203  half_lives.resize( decay_array.size() );
204  bifurcation.resize( decay_array.size() );
205 
206  int i_decay=0;
207  for (Input::Iterator<Input::Record> dec_it = decay_array.begin<Input::Record>(); dec_it != decay_array.end(); ++dec_it, ++i_decay)
208  {
209  //half-lives determining part
210  Input::Iterator<double> it_hl = dec_it->find<double>("half_life");
211  if (it_hl) {
212  half_lives[i_decay] = *it_hl;
213  } else {
214  it_hl = dec_it->find<double>("kinetic");
215  if (it_hl) {
216  half_lives[i_decay] = log(2)/(*it_hl);
217  } else {
218  xprintf(UsrErr, "Missing half-life or kinetic in the %d-th reaction.\n", i_decay);
219  }
220  }
221 
222  //indices determining part
223  string parent_name = dec_it->val<string>("parent");
224  Input::Array product_array = dec_it->val<Input::Array>("products");
225  Input::Array ratio_array = dec_it->val<Input::Array>("branch_ratios"); // has default value [ 1.0 ]
226 
227  // substance_ids contains also parent id
228  if (product_array.size() > 0) substance_ids[i_decay].resize( product_array.size()+1 );
229  else xprintf(UsrErr,"Empty array of products in the %d-th reaction.\n", i_decay);
230 
231 
232  // set parent index
233  idx = find_subst_name(parent_name);
234  if (idx < names_.size()) substance_ids[i_decay][0] = idx;
235  else xprintf(UsrErr,"Wrong name of parent substance in the %d-th reaction.\n", i_decay);
236 
237  // set products
238  unsigned int i_product = 1;
239  for(Input::Iterator<string> product_it = product_array.begin<string>(); product_it != product_array.end(); ++product_it, i_product++)
240  {
241  idx = find_subst_name(*product_it);
242  if (idx < names_.size()) substance_ids[i_decay][i_product] = idx;
243  else xprintf(Msg,"Wrong name of %d-th product in the %d-th reaction.\n", i_product-1 , i_decay);
244  }
245 
246  //bifurcation determining part
247  if (ratio_array.size() == product_array.size() ) ratio_array.copy_to( bifurcation[i_decay] );
248  else xprintf(UsrErr,"Number of branches %d has to match number of products %d in the %d-th reaction.\n",
249  ratio_array.size(), product_array.size(), i_decay);
250 
251  }
252 }
253 
255 {
256  DBGMSG("LinearReactions - update solution\n");
257  if(time_->is_changed_dt())
258  {
262  }
263  //data_.set_time(*time_); // set to the last computed time
264  //if timestep changed then modify_reaction_matrix(), not implemented yet
265  //DBGMSG("decay step\n");
266  if (reaction_matrix == nullptr) return;
267 
268  START_TIMER("linear reaction step");
269  for (unsigned int loc_el = 0; loc_el < distribution->lsize(); loc_el++)
270  {
272 // if (dual_porosity_on == true) {
273 // this->compute_reaction(concentration_matrix[IMMOBILE], loc_el);
274 // }
275 
276  }
277  END_TIMER("linear reaction step");
278  return;
279 }
280 
282 {
283  if(reaction_matrix != nullptr)
284  {
285  for(unsigned int i = 0; i < names_.size(); i++)
286  {
287  if(reaction_matrix[i] != nullptr)
288  {
289  free(reaction_matrix[i]);
290  reaction_matrix[i] = nullptr;
291  }
292  }
293  free(reaction_matrix);
294  reaction_matrix = nullptr;
295  }
296 }
297 
299 {
300  unsigned int cols,rows;
301 
302  DBGMSG("r mat: %p\n", reaction_matrix);
303  if(reaction_matrix != nullptr){
304  if(time_ != NULL)
305  xprintf(Msg,"\ntime_step %f,Reaction matrix looks as follows:\n",time_->dt());
306  for(rows = 0; rows < names_.size(); rows++){
307  for(cols = 0; cols < names_.size(); cols++){
308  xprintf(Msg,"%f\t",reaction_matrix[rows][cols]);
309  }
310  xprintf(Msg,"\n");
311  }
312  }else{
313  xprintf(Msg,"\nReaction matrix needs to be allocated.\n");
314  }
315  return;
316 }
317 
318 unsigned int Linear_reaction::find_subst_name(const string &name)
319 {
320 
321  unsigned int k=0;
322  for(; k < names_.size(); k++)
323  if (name == names_[k]) return k;
324 
325  return k;
326 }