Flow123d
pade_approximant.cc
Go to the documentation of this file.
1 #include <iostream>
2 #include <cstring>
3 #include <stdlib.h>
4 #include <math.h>
5 #include "reaction/reaction.hh"
8 #include "system/system.hh"
9 //#include "transport/transport.h"
10 //#include "system/par_distribution.hh"
11 #include "la/distribution.hh"
12 #include "mesh/mesh.h"
13 
14 #define MOBILE 0
15 #define IMMOBILE 1
16 
17 using namespace Input::Type;
18 
20  = Record("Substep", "Equation for reading information about radioactive decays.")
21  .declare_key("parent", String(), Default::obligatory(),
22  "Identifier of an isotope.")
23  .declare_key("half_life", Double(), Default::optional(),
24  "Half life of the parent substance.")
25  .declare_key("kinetic", Double(), Default::optional(),
26  "Kinetic constants describing first order reactions.")
27  .declare_key("products", Array(String()), Default::obligatory(),
28  "Identifies isotopes which decays parental atom to.")
29  .declare_key("branch_ratios", Array(Double()), Default("1.0"), // default is one product, with ratio == 1.0
30  "Decay chain branching percentage.");
31 
32 
34  = Record("PadeApproximant", "Abstract record with an information about pade approximant parameters.")
37  "Description of particular decay chain substeps.")
38  .declare_key("nom_pol_deg", Integer(), Default("2"),
39  "Polynomial degree of the nominator of Pade approximant.")
40  .declare_key("den_pol_deg", Integer(), Default("2"),
41  "Polynomial degree of the nominator of Pade approximant");
42 
43 
44 using namespace std;
45 
46 
48  : Linear_reaction(init_mesh, in_rec)
49 {
50 }
51 
53 {
54  /*int i, rows, n_subst;
55 
56  if(half_lives != NULL){
57  free(half_lives);
58  half_lives = NULL;
59  }
60 
61  if(substance_ids != NULL){
62  free(substance_ids);
63  substance_ids = NULL;
64  }
65 
66  release_reaction_matrix();*/
67 
68  DBGMSG("Pade approximant destructor is running.\n");
69 }
70 
72 {
73 
75 
76  // init from input
77  nom_pol_deg = input_record_.val<int>("nom_pol_deg");
78  den_pol_deg = input_record_.val<int>("den_pol_deg");
79  if((nom_pol_deg + den_pol_deg) < 0){
80  xprintf(UsrErr, "You did not specify Pade approximant required polynomial degrees.");
81  //TODO: This occasion should cause an error.
82  }
83 }
84 
85 double **Pade_approximant::allocate_reaction_matrix(void) //reaction matrix initialization
86 {
87  unsigned int rows, cols;
88 
89  cout << "We are going to allocate reaction matrix" << endl;
90  if (reaction_matrix == NULL) reaction_matrix = (double **)xmalloc(names_.size() * sizeof(double*));//allocation section
91  for(rows = 0; rows < names_.size(); rows++){
92  reaction_matrix[rows] = (double *)xmalloc(names_.size() * sizeof(double));
93  }
94  for(rows = 0; rows < names_.size();rows++){
95  for(cols = 0; cols < names_.size(); cols++){
96  reaction_matrix[rows][cols] = 0.0;
97  }
98  }
100  return reaction_matrix;
101 }
102 
104 {
105  Mat Denominator;
106  Mat Nominator;
107  //Mat Reaction_matrix;
108  Mat Pade_approximant;
109  //MatFactorInfo matfact;
110  PC Precond;
111  //IS rperm, cperm;
112  Vec tmp1; //contains the information about concentrations of all the species in one particular element
113  Vec tmp2; //the same as tmp1
114  //PetscInt n, m = 2;
115  PetscScalar nominator_coef[nom_pol_deg];
116  PetscScalar denominator_coef[den_pol_deg];
117  PetscScalar Hlp_mat[1];
118  PetscScalar *Array_hlp;
119  //const PetscScalar *Reaction_matrix_row;
120  //char dec_name[30];
121  int rows, cols, i, j; //int dec_nr, dec_name_nr = 1, index, prev_index;
122 
123  //create the matrix Reaction_matrix
124  MatCreate(PETSC_COMM_SELF, &Reaction_matrix);
125  MatSetSizes(Reaction_matrix, PETSC_DECIDE, PETSC_DECIDE, names_.size(), names_.size()); //should be probably multiplied by 2 (which is the value of m)
126  MatSetType(Reaction_matrix, MATAIJ);
127  MatSetUp(Reaction_matrix);
128 
129 
130  //It is necessery to initialize reaction matrix here
131  int index_par;
132  int index_child;
133  PetscScalar rel_step;
134  PetscScalar extent;
135  for (unsigned int i_decay = 0; i_decay < half_lives.size(); i_decay++) {
136  index_par = substance_ids[i_decay][0];
137  rel_step = time_->dt() / half_lives[i_decay];
138  extent = -log(2)*rel_step; //pow(0.5, rel_step);
139  cout<<"parental index" << index_par << ", extent "<< extent << endl;
140  MatSetValue(Reaction_matrix, index_par, index_par, extent,INSERT_VALUES);
141  for (unsigned int i_product = 1; i_product < substance_ids[i_decay].size(); ++i_product){
142  //reaction_matrix[index_par][ substance_ids[i_decay][i_product] ]
143  extent = log(2)*rel_step* bifurcation[i_decay][i_product-1];
144  index_child = substance_ids[i_decay][i_product];
145  MatSetValue(Reaction_matrix, index_par, index_child,extent,INSERT_VALUES);
146  }
147  }
148 
149  MatAssemblyBegin(Reaction_matrix, MAT_FINAL_ASSEMBLY);
150  MatAssemblyEnd(Reaction_matrix, MAT_FINAL_ASSEMBLY);
151 
152  //create the matrix N
153  MatDuplicate(Reaction_matrix, MAT_DO_NOT_COPY_VALUES, &Nominator);
154 
155  //create the matrix D
156  MatDuplicate(Reaction_matrix, MAT_DO_NOT_COPY_VALUES, &Denominator);
157 
158 
159  //Computation of nominator in pade approximant follows
160  MatZeroEntries(Nominator);
161  //MatAssemblyBegin(Nominator, MAT_FINAL_ASSEMBLY);
162  //MatAssemblyEnd(Nominator, MAT_FINAL_ASSEMBLY);
163  for(j = nom_pol_deg; j >= 0; j--)
164  {
165  nominator_coef[j] = (PetscScalar) (factorial(nom_pol_deg + den_pol_deg - j) * factorial(nom_pol_deg)) / (factorial(nom_pol_deg + den_pol_deg) * factorial(j) * factorial(nom_pol_deg - j));
166  }
167  evaluate_matrix_polynomial(&Nominator, &Reaction_matrix, nominator_coef);
168  //MatView(Nominator,PETSC_VIEWER_STDOUT_WORLD);
169 
170  //Computation of denominator in pade approximant follows
171  MatZeroEntries(Denominator);
172  //MatAssemblyBegin(Denominator, MAT_FINAL_ASSEMBLY);
173  //MatAssemblyEnd(Denominator, MAT_FINAL_ASSEMBLY);
174  for(i = den_pol_deg; i >= 0; i--)
175  {
176  denominator_coef[i] = (PetscScalar) pow(-1.0,i) * factorial(nom_pol_deg + den_pol_deg - i) * factorial(den_pol_deg) / (factorial(nom_pol_deg + den_pol_deg) * factorial(i) * factorial(den_pol_deg - i));
177  }
178  evaluate_matrix_polynomial(&Denominator, &Reaction_matrix, denominator_coef);
179  //MatView(Denominator, PETSC_VIEWER_STDOUT_WORLD);
180 
181 
182 
183  PCCreate(PETSC_COMM_WORLD, &Precond);
184  PCSetType(Precond, PCLU);
185  PCSetOperators(Precond, Denominator, Denominator, DIFFERENT_NONZERO_PATTERN);
186  //PCFactorSetMatOrderingType(Precond, MATORDERINGNATURAL);
187  PCFactorSetMatOrderingType(Precond, MATORDERINGRCM);
188  PCSetUp(Precond);
189 
190  VecCreate(PETSC_COMM_WORLD, &tmp1);
191  VecSetSizes(tmp1, PETSC_DECIDE, names_.size());
192  VecSetFromOptions(tmp1);
193  VecDuplicate(tmp1, &tmp2);
194 
195 
196  //create the matrix pade
197  MatCreate(PETSC_COMM_SELF, &Pade_approximant);
198  MatSetSizes(Pade_approximant, PETSC_DECIDE, PETSC_DECIDE, names_.size(), names_.size()); //should be probably multiplied by 2 (which is the value of m)
199  MatSetType(Pade_approximant, MATAIJ);
200  MatSetUp(Pade_approximant);
201 
202  for(rows = 0; rows < (int)( names_.size() ); rows++){
203  MatGetColumnVector(Nominator, tmp1, rows);
204  //VecView(tmp1, PETSC_VIEWER_STDOUT_SELF);
205  PCApply(Precond, tmp1, tmp2);
206  PCView(Precond, PETSC_VIEWER_STDOUT_WORLD);
207  //VecView(tmp2, PETSC_VIEWER_STDOUT_SELF);
208  VecGetArray(tmp2, &Array_hlp);
209  for(cols = 0; cols < (int)( names_.size() ); cols++)
210  {
211  MatSetValue(Pade_approximant, rows, cols, Array_hlp[cols], ADD_VALUES);
212  }
213  }
214  MatAssemblyBegin(Pade_approximant, MAT_FINAL_ASSEMBLY);
215  MatAssemblyEnd(Pade_approximant, MAT_FINAL_ASSEMBLY);
216 
217  //pade assembled to reaction_matrix
218  for(rows = 0; rows < (int)( names_.size() ); rows++)
219  {
220  for(cols = 0; cols < (int)( names_.size() ); cols++)
221  {
222  reaction_matrix[rows][cols] = 0.0;
223  }
224  }
225  for(rows = 0; rows < (int)( names_.size() ); rows++)
226  {
227  for(cols = 0; cols < (int)( names_.size() ); cols++)
228  {
229  MatGetValues(Pade_approximant, 1, &rows, 1, &cols, Hlp_mat); //&Hlp_mat[names_.size()*rows + cols]);
230  reaction_matrix[rows][cols] = (double) (Hlp_mat[0]);
231  }
232  }
233 
234  print_reaction_matrix(); //for visual control of equality of reaction_matrix in comparison with pade aproximant*/
235 
236  VecDestroy(&tmp1);
237  VecDestroy(&tmp2);
238  PCDestroy(&Precond);
239  MatDestroy(&Denominator);
240  MatDestroy(&Nominator);
241  //MatDestroy(Reaction_matrix);
242  MatDestroy(&Pade_approximant);
243 
244  return reaction_matrix;
245 }
246 
247 void Pade_approximant::evaluate_matrix_polynomial(Mat *Polynomial, Mat *Reaction_matrix, PetscScalar *coef)
248 {
249  Mat Identity;
250 
251  //create Identity matrix
252  MatCreate(PETSC_COMM_SELF, &Identity);
253  MatSetSizes(Identity, PETSC_DECIDE, PETSC_DECIDE, names_.size(), names_.size()); //should be probably multiplied by 2 (which is the value of m)
254  MatSetType(Identity, MATAIJ);
255  MatSetUp(Identity);
256 
257  MatAssemblyBegin(Identity, MAT_FINAL_ASSEMBLY);
258  MatAssemblyEnd(Identity, MAT_FINAL_ASSEMBLY);
259  MatShift(Identity, 1.0);
260 
261  for(int i = den_pol_deg; i >= 0; i--)
262  {
263  MatMatMult(*Polynomial, *Reaction_matrix, MAT_INITIAL_MATRIX, PETSC_DEFAULT, Polynomial);
264  MatAXPY(*Polynomial, coef[i], Identity, DIFFERENT_NONZERO_PATTERN);
265  }
266 
267  MatDestroy(&Identity);
268 
269  return;
270 }
271 
272 
273 double **Pade_approximant::compute_reaction(double **concentrations, int loc_el) //multiplication of concentrations array by reaction matrix
274 {
275  unsigned int cols, rows;
276 
277  if (reaction_matrix == NULL) return concentrations;
278 
279  for(cols = 0; cols < names_.size(); cols++){
280  prev_conc[cols] = concentrations[cols][loc_el];
281  concentrations[cols][loc_el] = 0.0;
282  }
283 
284  for(cols = 0; cols < names_.size(); cols++){
285  for(rows = 0; rows < names_.size(); rows++){
286  concentrations[cols][loc_el] += reaction_matrix[cols][rows]*prev_conc[rows];
287  }
288  }
289 
290  return concentrations;
291 }
292 
293 
294 
296 {
297  int faktor = 1;
298 
299  if(k < 0)
300  {
301  //an error message should be placed here
302  return 0;
303  }
304 
305  while(k > 1)
306  {
307  faktor *= k;
308  k--;
309  }
310  //xprintf(Msg,"\n Koeficient has a value %d.\n",faktor);
311  return faktor;
312 }