Ice Sheet System Model  4.18
Code documentation
DenseGslSolve.cpp
Go to the documentation of this file.
1 
5 /*Header files: {{{*/
6 #ifdef HAVE_CONFIG_H
7  #include <config.h>
8 #else
9 #error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
10 #endif
11 
12 #include "../../shared/shared.h"
13 #include "../../classes/Params/GenericParam.h"
14 #include "../../classes/Params/Parameters.h"
15 #include "../adolc/adolcincludes.h"
16 #include "../codipack/codipackincludes.h"
17 #include "./gslincludes.h"
18 
19 #ifdef _HAVE_GSL_
20 #include <gsl/gsl_linalg.h>
21 #endif
22 
23 /*}}}*/
24 
25 void DenseGslSolve(IssmPDouble** pX,IssmPDouble* A,IssmPDouble* B, int n){ /*{{{*/
26 
27  /*Intermediary: */
28  IssmPDouble *X = xNew<IssmPDouble>(n);
29  SolverxSeq(X,A,B,n);
30 
31  /*allocate output pointers: */
32  *pX=X;
33 }
34 /*}}}*/
35 void DenseGslSolve(IssmPDouble** px,IssmPDouble* Kff,int Kff_M,int Kff_N,IssmPDouble* pf,int pf_M,Parameters* parameters){ /*{{{*/
36 
37  /*Intermediary: */
38 
39  if(Kff_N!=pf_M)_error_("Right hand side vector of size " << pf_M << ", when matrix is of size " << Kff_M << "-" << Kff_N << " !");
40  if(Kff_M!=Kff_N)_error_("Stiffness matrix should be square!");
41 
42  IssmPDouble *x = xNew<IssmPDouble>(Kff_N);
43  SolverxSeq(x,Kff,pf,Kff_N);
44 
45  /*allocate output pointers: */
46  *px=x;
47 }
48 /*}}}*/
49 void SolverxSeq(IssmPDouble *X, IssmPDouble *A, IssmPDouble *B,int n){ /*{{{*/
50 #ifdef _HAVE_GSL_
51  /*GSL Matrices and vectors: */
52  int s;
53  gsl_matrix_view a;
54  gsl_vector_view b,x;
55  gsl_permutation *p = NULL;
56 // for (int i=0; i<n*n; ++i) std::cout << "SolverxSeq A["<< i << "]=" << A[i] << std::endl;
57 // for (int i=0; i<n; ++i) std::cout << "SolverxSeq b["<< i << "]=" << B[i] << std::endl;
58  /*A will be modified by LU decomposition. Use copy*/
59  double* Acopy = xNew<double>(n*n);
60  xMemCpy(Acopy,A,n*n);
61 
62  /*Initialize gsl matrices and vectors: */
63  a = gsl_matrix_view_array (Acopy,n,n);
64  b = gsl_vector_view_array (B,n);
65  x = gsl_vector_view_array (X,n);
66 
67  /*Run LU and solve: */
68  p = gsl_permutation_alloc (n);
69  gsl_linalg_LU_decomp (&a.matrix, p, &s);
70  gsl_linalg_LU_solve (&a.matrix, p, &b.vector, &x.vector);
71 
72  /*Clean up and assign output pointer*/
73  xDelete(Acopy);
74  gsl_permutation_free(p);
75 #endif
76 }
77 /*}}}*/
78 
79 #ifdef _HAVE_ADOLC_
80 int EDF_for_solverx(int n, IssmPDouble *x, int m, IssmPDouble *y){ /*{{{*/
81  SolverxSeq(y,x, x+m*m, m); // x is where the matrix starts, x+m*m is where the right-hand side starts
82  return 0;
83 } /*}}}*/
84 int EDF_fos_forward_for_solverx(int n, IssmPDouble *inVal, IssmPDouble *inDeriv, int m, IssmPDouble *outVal, IssmPDouble *outDeriv) { /*{{{*/
85 #ifdef _HAVE_GSL_
86  // for (int i=0; i<m*m; ++i) std::cout << "EDF_fos_forward_for_solverx A["<< i << "]=" << inVal[i] << std::endl;
87  // for (int i=0; i<m; ++i) std::cout << "EDF_fos_forward_for_solverx b["<< i << "]=" << inVal[i+m*m] << std::endl;
88  // the matrix will be modified by LU decomposition. Use gsl_A copy
89  double* Acopy = xNew<double>(m*m);
90  xMemCpy(Acopy,inVal,m*m);
91  /*Initialize gsl matrices and vectors: */
92  gsl_matrix_view gsl_A = gsl_matrix_view_array (Acopy,m,m);
93  gsl_vector_view gsl_b = gsl_vector_view_array (inVal+m*m,m); // the right hand side starts at address inVal+m*m
94  gsl_permutation *perm_p = gsl_permutation_alloc (m);
95  int signPerm;
96  // factorize
97  gsl_linalg_LU_decomp (&gsl_A.matrix, perm_p, &signPerm);
98  gsl_vector *gsl_x_p = gsl_vector_alloc (m);
99  // solve for the value
100  gsl_linalg_LU_solve (&gsl_A.matrix, perm_p, &gsl_b.vector, gsl_x_p);
101  /*Copy result*/
102  xMemCpy(outVal,gsl_vector_ptr(gsl_x_p,0),m);
103  gsl_vector_free(gsl_x_p);
104  // for (int i=0; i<m; ++i) std::cout << "EDF_fos_forward_for_solverx x["<< i << "]=" << outVal[i] << std::endl;
105  // solve for the derivatives acc. to A * dx = r with r=db - dA * x
106  // compute the RHS
107  double* r=xNew<double>(m);
108  for (int i=0; i<m; i++) {
109  r[i]=inDeriv[m*m+i]; // this is db[i]
110  for (int j=0;j<m; j++) {
111  r[i]-=inDeriv[i*m+j]*outVal[j]; // this is dA[i][j]*x[j]
112  }
113  }
114  gsl_vector_view gsl_r=gsl_vector_view_array(r,m);
115  gsl_vector *gsl_dx_p = gsl_vector_alloc(m);
116  gsl_linalg_LU_solve (&gsl_A.matrix, perm_p, &gsl_r.vector, gsl_dx_p);
117  xMemCpy(outDeriv,gsl_vector_ptr(gsl_dx_p,0),m);
118  gsl_vector_free(gsl_dx_p);
119  xDelete(r);
120  gsl_permutation_free(perm_p);
121  xDelete(Acopy);
122 #endif
123  return 0;
124 } /*}}}*/
125 int EDF_fov_forward_for_solverx(int n, IssmPDouble *inVal, int directionCount, IssmPDouble **inDeriv, int m, IssmPDouble *outVal, IssmPDouble **outDeriv) { /*{{{*/
126 #ifdef _HAVE_GSL_
127  // the matrix will be modified by LU decomposition. Use gsl_A copy
128  double* Acopy = xNew<double>(m*m);
129  xMemCpy(Acopy,inVal,m*m);
130  /*Initialize gsl matrices and vectors: */
131  gsl_matrix_view gsl_A = gsl_matrix_view_array (Acopy,m,m);
132  gsl_vector_view gsl_b = gsl_vector_view_array (inVal+m*m,m); // the right hand side starts at address inVal+m*m
133  gsl_permutation *perm_p = gsl_permutation_alloc (m);
134  int signPerm;
135  // factorize
136  gsl_linalg_LU_decomp (&gsl_A.matrix, perm_p, &signPerm);
137  gsl_vector *gsl_x_p = gsl_vector_alloc (m);
138  // solve for the value
139  gsl_linalg_LU_solve (&gsl_A.matrix, perm_p, &gsl_b.vector, gsl_x_p);
140  /*Copy result*/
141  xMemCpy(outVal,gsl_vector_ptr(gsl_x_p,0),m);
142  gsl_vector_free(gsl_x_p);
143  // solve for the derivatives acc. to A * dx = r with r=db - dA * x
144  double* r=xNew<double>(m);
145  gsl_vector *gsl_dx_p = gsl_vector_alloc(m);
146  for (int dir=0;dir<directionCount;++dir) {
147  // compute the RHS
148  for (int i=0; i<m; i++) {
149  r[i]=inDeriv[m*m+i][dir]; // this is db[i]
150  for (int j=0;j<m; j++) {
151  r[i]-=inDeriv[i*m+j][dir]*outVal[j]; // this is dA[i][j]*x[j]
152  }
153  }
154  gsl_vector_view gsl_r=gsl_vector_view_array(r,m);
155  gsl_linalg_LU_solve (&gsl_A.matrix, perm_p, &gsl_r.vector, gsl_dx_p);
156  // reuse r
157  xMemCpy(r,gsl_vector_ptr(gsl_dx_p,0),m);
158  for (int i=0; i<m; i++) {
159  outDeriv[i][dir]=r[i];
160  }
161  }
162  gsl_vector_free(gsl_dx_p);
163  xDelete(r);
164  gsl_permutation_free(perm_p);
165  xDelete(Acopy);
166 #endif
167  return 0;
168 }
169 /*}}}*/
170 int EDF_fos_reverse_for_solverx(int m, double *dp_U, int n, double *dp_Z, double* dp_x, double* dp_y) { /*{{{*/
171  // copy to transpose the matrix
172  double* transposed=xNew<double>(m*m);
173  for (int i=0; i<m; ++i) for (int j=0; j<m; ++j) transposed[j*m+i]=dp_x[i*m+j];
174  gsl_matrix_view aTransposed = gsl_matrix_view_array (transposed,m,m);
175  // the adjoint of the solution is our right-hand side
176  gsl_vector_view x_bar=gsl_vector_view_array(dp_U,m);
177  // the last m elements of dp_Z representing the adjoint of the right-hand side we want to compute:
178  gsl_vector_view b_bar=gsl_vector_view_array(dp_Z+m*m,m);
179  gsl_permutation *perm_p = gsl_permutation_alloc (m);
180  int permSign;
181  gsl_linalg_LU_decomp (&aTransposed.matrix, perm_p, &permSign);
182  gsl_linalg_LU_solve (&aTransposed.matrix, perm_p, &x_bar.vector, &b_bar.vector);
183  // now do the adjoint of the matrix
184  for (int i=0; i<m; ++i) for (int j=0; j<m; ++j) dp_Z[i*m+j]-=dp_Z[m*m+i]*dp_y[j];
185  gsl_permutation_free(perm_p);
186  xDelete(transposed);
187  return 0;
188 }
189 /*}}}*/
190 int EDF_fov_reverse_for_solverx(int m, int p, double **dpp_U, int n, double **dpp_Z, double* dp_x, double* dp_y) { /*{{{*/
191  // copy to transpose the matrix
192  double* transposed=xNew<double>(m*m);
193  for (int i=0; i<m; ++i) for (int j=0; j<m; ++j) transposed[j*m+i]=dp_x[i*m+j];
194  gsl_matrix_view aTransposed = gsl_matrix_view_array (transposed,m,m);
195  gsl_permutation *perm_p = gsl_permutation_alloc (m);
196  int permSign;
197  gsl_linalg_LU_decomp (&aTransposed.matrix, perm_p, &permSign);
198  for (int weightsRowIndex=0;weightsRowIndex<p;++weightsRowIndex) {
199  // the adjoint of the solution is our right-hand side
200  gsl_vector_view x_bar=gsl_vector_view_array(dpp_U[weightsRowIndex],m);
201  // the last m elements of dp_Z representing the adjoint of the right-hand side we want to compute:
202  gsl_vector_view b_bar=gsl_vector_view_array(dpp_Z[weightsRowIndex]+m*m,m);
203  gsl_linalg_LU_solve (&aTransposed.matrix, perm_p, &x_bar.vector, &b_bar.vector);
204  // now do the adjoint of the matrix
205  for (int i=0; i<m; ++i) for (int j=0; j<m; ++j) dpp_Z[weightsRowIndex][i*m+j]-=dpp_Z[weightsRowIndex][m*m+i]*dp_y[j];
206  }
207  gsl_permutation_free(perm_p);
208  xDelete(transposed);
209  return 0;
210 }
211 /*}}}*/
212 void DenseGslSolve(/*output*/ IssmDouble** px,/*stiffness matrix:*/ IssmDouble* Kff, int Kff_M, int Kff_N, /*right hand side load vector: */ IssmDouble* pf, int pf_M, Parameters* parameters){ /*{{{*/
213 
214  /*Intermediary: */
215 
216  if(Kff_N!=pf_M)_error_("Right hand side vector of size " << pf_M << ", when matrix is of size " << Kff_M << "-" << Kff_N << " !");
217  if(Kff_M!=Kff_N)_error_("Stiffness matrix should be square!");
218 
219 // AD performance is sensitive to calls to ensurecontiguous.
220 // Providing "t" will cause ensurecontiguous to be called.
221 #ifdef _HAVE_AD_
222  IssmDouble *x = xNew<IssmDouble>(Kff_N,"t");
223 #else
224  IssmDouble *x = xNew<IssmDouble>(Kff_N);
225 #endif
226 
227  SolverxSeq(x,Kff,pf,Kff_N,parameters);
228 
229  /*allocate output pointers: */
230  *px=x;
231 }
232 /*}}}*/
233 void SolverxSeq(IssmDouble *X,IssmDouble *A,IssmDouble *B,int n, Parameters* parameters){/*{{{*/
234  // pack inputs to conform to the EDF-prescribed interface
235 // AD performance is sensitive to calls to ensurecontiguous.
236 // Providing "t" will cause ensurecontiguous to be called.
237 #ifdef _HAVE_AD_
238  IssmDouble* adoubleEDFin=xNew<IssmDouble>(n*(n+1),"t");
239 #else
240  IssmDouble* adoubleEDFin=xNew<IssmDouble>(n*(n+1));
241 #endif
242  // packed inputs, i.e. matrix and right hand side
243  for(int i=0; i<n*n;i++)adoubleEDFin[i] =A[i]; // pack matrix
244  for(int i=0; i<n; i++)adoubleEDFin[i+n*n]=B[i]; // pack the right hand side
245  // call the wrapped solver through the registry entry we retrieve from parameters
246  call_ext_fct(xDynamicCast<GenericParam<Adolc_edf> * >(parameters->FindParamObject(AdolcParamEnum))->GetParameterValue().myEDF_for_solverx_p,
247  n*(n+1), adoubleEDFin,
248  n, X);
249  // for(int i=0; i<n; i++) {ADOLC_DUMP_MACRO(X[i]);}
250  xDelete(adoubleEDFin);
251 }
252 /*}}}*/
253 #endif
254 
255 #ifdef _HAVE_CODIPACK_
256 void SolverxSeq_codi_b(void* tape_in,void* data_in,void* ra) {/*{{{*/
257 
258  /*recast data_in and tape*/
259  codi::DataStore* data = (codi::DataStore*)data_in;
260  //IssmDouble::TapeType& tape = (IssmDouble::TapeType&)tape_in;
261  IssmDouble::TapeType& tape = IssmDouble::getGlobalTape();
262 
263  IssmDouble::Real* valueATrans;
264  IssmDouble::GradientData* indexATrans;
265  IssmDouble::GradientData* indexB;
266  IssmDouble::Real* valueX;
267  IssmDouble::GradientData* indexX;
268  int n;
269 
270  data->getData(valueATrans);
271  data->getData(indexATrans);
272  data->getData(indexB);
273  data->getData(valueX);
274  data->getData(indexX);
275  data->getData(n);
276 
277 
278  // create the adjoint vector for x and reset the adjoint values on the tape
279  IssmDouble::GradientValue* adjX = xNew<IssmDouble::GradientValue>(n);
280  getVectorAdjoint(tape, indexX, adjX, n);
281 
282  IssmDouble::GradientValue* sol = xNew<IssmDouble::GradientValue>(n);
283  SolverxSeq(sol, valueATrans, adjX, n);
284 
285  updateVectorAdjoint(tape, indexB, sol, n);
286  for(int i=0; i<n; ++i) {
287  for (int j=0; j<n; ++j) {
288  // we access the transposed matrix here because we stored the indices in a transposed way
289  updateAdjoint(tape, indexATrans[i*n+j], -sol[j]*valueX[i]);
290  }
291  }
292 
293  xDelete(sol);
294  xDelete(adjX);
295 }
296 /*}}}*/
297 void SolverxSeq_codi_delete(void* tape_in,void* data_in) {/*{{{*/
298 
299  /*recast data_in*/
300  codi::DataStore* data = (codi::DataStore*)data_in;
301 
302  IssmDouble::Real* valueATrans;
303  IssmDouble::GradientData* indexATrans;
304  IssmDouble::GradientData* indexB;
305  IssmDouble::Real* valueX;
306  IssmDouble::GradientData* indexX;
307  int n;
308 
309  data->getData(valueATrans);
310  data->getData(indexATrans);
311  data->getData(indexB);
312  data->getData(valueX);
313  data->getData(indexX);
314  data->getData(n);
315 
316  xDelete(valueATrans);
317  xDelete(indexATrans);
318  xDelete(indexB);
319  xDelete(valueX);
320  xDelete(indexX);
321 }
322 /*}}}*/
323 void SolverxSeq(IssmDouble *X,IssmDouble *A,IssmDouble *B,int n, Parameters* parameters){/*{{{*/
324  IssmDouble::TapeType& tape = IssmDouble::getGlobalTape();
325  codi::DataStore* dataHandler = NULL;
326 
327  if(tape.isActive()) {
328  dataHandler = new codi::DataStore();
329 
330  // create the index vector and the double data for A and B
331  IssmDouble::Real* valueATrans = xNew<IssmDouble::Real>(n*n);
332  IssmDouble::GradientData* indexATrans = xNew<IssmDouble::GradientData>(n*n);
333 
334  // read the data for matrix in a transposed fashion
335  for (int i=0; i<n; ++i) {
336  for (int j=0; j<n; ++j) {
337  getPrimalAndGradData(A[i*n+j], valueATrans[j*n+i], indexATrans[j*n+i]);
338  }
339  }
340 
341  // read the data from B (primal values are not required vor B
342  IssmDouble::GradientData* indexB = xNew<IssmDouble::GradientData>(n);
343  getVectorGradData(B, indexB, n);
344 
345  dataHandler->addData(valueATrans);
346  dataHandler->addData(indexATrans);
347  dataHandler->addData(indexB);
348  }
349 
350  // unpack the primal values from the matrix and the vector
351  IssmDouble::Real* valueA = xNew<IssmDouble::Real>(n*n);
352  IssmDouble::Real* valueB = xNew<IssmDouble::Real>(n);
353  // read the data from A and B
354  getVectorPrimal(A, valueA, n*n);
355  getVectorPrimal(B, valueB, n);
356 
357  // create the placeholder for X and solve the system
358  IssmDouble::Real* valueX = xNew<IssmDouble::Real>(n);
359  SolverxSeq(valueX, valueA, valueB, n);
360 
361  // pack the values into x
362  setVectorPrimal(X, valueX, n);
363 
364  if(tape.isActive()) {
365  // create the index vector X and register x as active variables
366  IssmDouble::GradientData* indexX = xNew<IssmDouble::GradientData>(n);
367  registerVector(X, indexX, n);
368 
369  dataHandler->addData(valueX);
370  dataHandler->addData(indexX);
371 
372  // store other arguments
373  dataHandler->addData(n);
374 
375  tape.pushExternalFunctionHandle(&SolverxSeq_codi_b, dataHandler, &SolverxSeq_codi_delete);
376  } else {
377  // if the tape is active valueX is stored in the dataHandler and deleted in the reverse sweep
378  xDelete(valueX);
379  }
380 
381  xDelete(valueB);
382  xDelete(valueA);
383 }
384 /*}}}*/
385 void DenseGslSolve(/*output*/ IssmDouble** px,/*stiffness matrix:*/ IssmDouble* Kff, int Kff_M, int Kff_N, /*right hand side load vector: */ IssmDouble* pf, int pf_M, Parameters* parameters){ /*{{{*/
386 
387  /*Intermediary: */
388 
389  if(Kff_N!=pf_M)_error_("Right hand side vector of size " << pf_M << ", when matrix is of size " << Kff_M << "-" << Kff_N << " !");
390  if(Kff_M!=Kff_N)_error_("Stiffness matrix should be square!");
391 
392  IssmDouble *x = xNew<IssmDouble>(Kff_N,"t");
393 
394  SolverxSeq(x,Kff,pf,Kff_N,parameters);
395 
396  /*allocate output pointers: */
397  *px=x;
398 }
399 /*}}}*/
400 #endif
xDynamicCast
To xDynamicCast(const From &from)
Definition: recast.h:51
IssmDouble
double IssmDouble
Definition: types.h:37
Parameters
Declaration of Parameters class.
Definition: Parameters.h:18
GenericParam::GetParameterValue
P & GetParameterValue()
Definition: GenericParam.h:62
xDelete
void xDelete(T **&aT_pp)
Definition: MemOps.h:97
_error_
#define _error_(StreamArgs)
Definition: exceptions.h:49
gslincludes.h
AdolcParamEnum
@ AdolcParamEnum
Definition: EnumDefinitions.h:12
SolverxSeq
void SolverxSeq(IssmPDouble *X, IssmPDouble *A, IssmPDouble *B, int n)
Definition: DenseGslSolve.cpp:49
DenseGslSolve
void DenseGslSolve(IssmPDouble **pX, IssmPDouble *A, IssmPDouble *B, int n)
Definition: DenseGslSolve.cpp:25
xMemCpy
T * xMemCpy(T *dest, const T *src, unsigned int size)
Definition: MemOps.h:152
IssmPDouble
IssmDouble IssmPDouble
Definition: types.h:38
Parameters::FindParamObject
Param * FindParamObject(int enum_type)
Definition: Parameters.cpp:588
GenericParam
Definition: GenericParam.h:26