MueLu  Version of the Day
MueLu_MatlabUtils_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 
47 #ifndef MUELU_MATLABUTILS_DEF_HPP
48 #define MUELU_MATLABUTILS_DEF_HPP
49 
51 
52 #if !defined(HAVE_MUELU_MATLAB) || !defined(HAVE_MUELU_EPETRA) || !defined(HAVE_MUELU_TPETRA)
53 #error "Muemex types require MATLAB, Epetra and Tpetra."
54 #else
55 
56 using Teuchos::RCP;
57 using Teuchos::rcp;
58 using namespace std;
59 
60 namespace MueLu {
61 
62 extern bool rewrap_ints;
63 
64 /* ******************************* */
65 /* getMuemexType */
66 /* ******************************* */
67 
68 template<typename T> MuemexType getMuemexType(const T & data) {throw std::runtime_error("Unknown Type");}
69 
70 template<> MuemexType getMuemexType(const int & data) {return INT;}
71 template<> MuemexType getMuemexType<int>() {return INT;}
72 template<> MuemexType getMuemexType<bool>() {return BOOL;}
73 
74 template<> MuemexType getMuemexType(const double & data) {return DOUBLE;}
75 template<> MuemexType getMuemexType<double>() {return DOUBLE;}
76 
77 template<> MuemexType getMuemexType(const std::string & data) {return STRING;}
78 template<> MuemexType getMuemexType<string>() {return STRING;}
79 
80 template<> MuemexType getMuemexType(const complex_t& data) {return COMPLEX;}
82 
83 template<> MuemexType getMuemexType(const RCP<Xpetra_map> & data) {return XPETRA_MAP;}
84 template<> MuemexType getMuemexType<RCP<Xpetra_map> >() {return XPETRA_MAP;}
85 
86 template<> MuemexType getMuemexType(const RCP<Xpetra_ordinal_vector> & data) {return XPETRA_ORDINAL_VECTOR;}
87 template<> MuemexType getMuemexType<RCP<Xpetra_ordinal_vector>>() {return XPETRA_ORDINAL_VECTOR;}
88 
89 template<> MuemexType getMuemexType(const RCP<Tpetra_MultiVector_double> & data) {return TPETRA_MULTIVECTOR_DOUBLE;}
90 template<> MuemexType getMuemexType<RCP<Tpetra_MultiVector_double>>() {return TPETRA_MULTIVECTOR_DOUBLE;}
91 
92 template<> MuemexType getMuemexType(const RCP<Tpetra_MultiVector_complex>& data) {return TPETRA_MULTIVECTOR_COMPLEX;}
93 template<> MuemexType getMuemexType<RCP<Tpetra_MultiVector_complex>>() {return TPETRA_MULTIVECTOR_COMPLEX;}
94 
95 template<> MuemexType getMuemexType(const RCP<Tpetra_CrsMatrix_double> & data) {return TPETRA_MATRIX_DOUBLE;}
96 template<> MuemexType getMuemexType<RCP<Tpetra_CrsMatrix_double>>() {return TPETRA_MATRIX_DOUBLE;}
97 
98 template<> MuemexType getMuemexType(const RCP<Tpetra_CrsMatrix_complex> & data) {return TPETRA_MATRIX_COMPLEX;}
99 template<> MuemexType getMuemexType<RCP<Tpetra_CrsMatrix_complex>>() {return TPETRA_MATRIX_COMPLEX;}
100 
101 template<> MuemexType getMuemexType(const RCP<Xpetra_MultiVector_double> & data) {return XPETRA_MULTIVECTOR_DOUBLE;}
102 template<> MuemexType getMuemexType<RCP<Xpetra_MultiVector_double>>() {return XPETRA_MULTIVECTOR_DOUBLE;}
103 
104 template<> MuemexType getMuemexType(const RCP<Xpetra_MultiVector_complex> & data) {return XPETRA_MULTIVECTOR_COMPLEX;}
105 template<> MuemexType getMuemexType<RCP<Xpetra_MultiVector_complex>>() {return XPETRA_MULTIVECTOR_COMPLEX;}
106 
107 template<> MuemexType getMuemexType(const RCP<Xpetra_Matrix_double> & data) {return XPETRA_MATRIX_DOUBLE;}
108 template<> MuemexType getMuemexType<RCP<Xpetra_Matrix_double>>() {return XPETRA_MATRIX_DOUBLE;}
109 
110 template<> MuemexType getMuemexType(const RCP<Xpetra_Matrix_complex> & data) {return XPETRA_MATRIX_COMPLEX;}
111 template<> MuemexType getMuemexType<RCP<Xpetra_Matrix_complex>>() {return XPETRA_MATRIX_COMPLEX;}
112 
113 template<> MuemexType getMuemexType(const RCP<Epetra_CrsMatrix> & data) {return EPETRA_CRSMATRIX;}
114 template<> MuemexType getMuemexType<RCP<Epetra_CrsMatrix>>() {return EPETRA_CRSMATRIX;}
115 
116 template<> MuemexType getMuemexType(const RCP<Epetra_MultiVector> & data) {return EPETRA_MULTIVECTOR;}
117 template<> MuemexType getMuemexType<RCP<Epetra_MultiVector>>() {return EPETRA_MULTIVECTOR;}
118 
119 template<> MuemexType getMuemexType(const RCP<MAggregates>& data) {return AGGREGATES;}
120 template<> MuemexType getMuemexType<RCP<MAggregates>>() {return AGGREGATES;}
121 
122 template<> MuemexType getMuemexType(const RCP<MAmalInfo>& data) {return AMALGAMATION_INFO;}
123 template<> MuemexType getMuemexType<RCP<MAmalInfo>>() {return AMALGAMATION_INFO;}
124 
125 template<> MuemexType getMuemexType(const RCP<MGraph>& data) {return GRAPH;}
126 template<> MuemexType getMuemexType<RCP<MGraph>>() {return GRAPH;}
127 
128 #ifdef HAVE_MUELU_INTREPID2
129 template<> MuemexType getMuemexType(const RCP<FieldContainer_ordinal>& data) {return FIELDCONTAINER_ORDINAL;}
130 template<> MuemexType getMuemexType<RCP<FieldContainer_ordinal>>() {return FIELDCONTAINER_ORDINAL;}
131 #endif
132 
133 /* "prototypes" for specialized functions used in other specialized functions */
134 
135 template<> mxArray* createMatlabSparse<double>(int numRows, int numCols, int nnz);
136 template<> mxArray* createMatlabSparse<complex_t>(int numRows, int numCols, int nnz);
137 template<> mxArray* createMatlabMultiVector<double>(int numRows, int numCols);
138 template<> mxArray* createMatlabMultiVector<complex_t>(int numRows, int numCols);
139 template<> void fillMatlabArray<double>(double* array, const mxArray* mxa, int n);
140 template<> void fillMatlabArray<complex_t>(complex_t* array, const mxArray* mxa, int n);
141 template<> mxArray* saveDataToMatlab(RCP<Xpetra_MultiVector_double>& data);
142 template<> mxArray* saveDataToMatlab(RCP<Xpetra_MultiVector_complex>& data);
143 template<> mxArray* saveDataToMatlab(RCP<Xpetra_Matrix_double>& data);
144 template<> mxArray* saveDataToMatlab(RCP<Xpetra_Matrix_complex>& data);
145 
146 /* ******************************* */
147 /* loadDataFromMatlab */
148 /* ******************************* */
149 
150 template<>
151 int loadDataFromMatlab<int>(const mxArray* mxa)
152 {
153  mxClassID probIDtype = mxGetClassID(mxa);
154  int rv;
155  if(probIDtype == mxINT32_CLASS)
156  {
157  rv = *((int*) mxGetData(mxa));
158  }
159  else if(probIDtype == mxLOGICAL_CLASS)
160  {
161  rv = (int) *((bool*) mxGetData(mxa));
162  }
163  else if(probIDtype == mxDOUBLE_CLASS)
164  {
165  rv = (int) *((double*) mxGetData(mxa));
166  }
167  else if(probIDtype == mxUINT32_CLASS)
168  {
169  rv = (int) *((unsigned int*) mxGetData(mxa));
170  }
171  else
172  {
173  rv = -1;
174  throw std::runtime_error("Error: Unrecognized numerical type.");
175  }
176  return rv;
177 }
178 
179 template<>
180 bool loadDataFromMatlab<bool>(const mxArray* mxa)
181 {
182  return *((bool*) mxGetData(mxa));
183 }
184 
185 template<>
186 double loadDataFromMatlab<double>(const mxArray* mxa)
187 {
188  return *((double*) mxGetPr(mxa));
189 }
190 
191 template<>
193 {
194  double realpart = real<double>(*((double*) mxGetPr(mxa)));
195  double imagpart = imag<double>(*((double*) mxGetPi(mxa)));
196  return complex_t(realpart, imagpart);
197 }
198 
199 template<>
200 string loadDataFromMatlab<string>(const mxArray* mxa)
201 {
202  string rv = "";
203  if (mxGetClassID(mxa) != mxCHAR_CLASS)
204  {
205  throw runtime_error("Can't construct string from anything but a char array.");
206  }
207  rv = string(mxArrayToString(mxa));
208  return rv;
209 }
210 
211 template<>
212 RCP<Xpetra_map> loadDataFromMatlab<RCP<Xpetra_map>>(const mxArray* mxa)
213 {
214  RCP<const Teuchos::Comm<int> > comm = rcp(new Teuchos::SerialComm<int>());
215  int nr = mxGetM(mxa);
216  int nc = mxGetN(mxa);
217  if(nr != 1)
218  throw std::runtime_error("A Xpetra::Map representation from MATLAB must be a single row vector.");
219  double* pr = mxGetPr(mxa);
220  mm_GlobalOrd numGlobalIndices = nc;
221 
222  std::vector<mm_GlobalOrd> localGIDs(numGlobalIndices);
223  for(int i = 0; i < int(numGlobalIndices); i++) {
224  localGIDs[i] = Teuchos::as<mm_GlobalOrd>(pr[i]);
225  }
226 
227  const Teuchos::ArrayView<const mm_GlobalOrd> localGIDs_view(&localGIDs[0],localGIDs.size());
228  RCP<Xpetra_map> map =
229  Xpetra::MapFactory<mm_LocalOrd, mm_GlobalOrd, mm_node_t>::Build(
230  Xpetra::UseTpetra,
231  Teuchos::OrdinalTraits<mm_GlobalOrd>::invalid(),
232  localGIDs_view,
233  0, comm);
234 
235  if(map.is_null())
236  throw runtime_error("Failed to create Xpetra::Map.");
237  return map;
238 }
239 
240 template<>
241 RCP<Xpetra_ordinal_vector> loadDataFromMatlab<RCP<Xpetra_ordinal_vector>>(const mxArray* mxa)
242 {
243  RCP<const Teuchos::Comm<int> > comm = rcp(new Teuchos::SerialComm<int>());
244  if(mxGetN(mxa) != 1 && mxGetM(mxa) != 1)
245  throw std::runtime_error("An OrdinalVector from MATLAB must be a single row or column vector.");
246  mm_GlobalOrd numGlobalIndices = mxGetM(mxa) * mxGetN(mxa);
247  RCP<Xpetra::Map<mm_LocalOrd, mm_GlobalOrd, mm_node_t>> map = Xpetra::MapFactory<mm_LocalOrd, mm_GlobalOrd, mm_node_t>::Build(Xpetra::UseTpetra, numGlobalIndices, 0, comm);
248  if(mxGetClassID(mxa) != mxINT32_CLASS)
249  throw std::runtime_error("Can only construct LOVector with int32 data.");
250  int* array = (int*) mxGetData(mxa);
251  if(map.is_null())
252  throw runtime_error("Failed to create map for Xpetra ordinal vector.");
253  RCP<Xpetra_ordinal_vector> loVec = Xpetra::VectorFactory<mm_LocalOrd, mm_LocalOrd, mm_GlobalOrd, mm_node_t>::Build(map, false);
254  if(loVec.is_null())
255  throw runtime_error("Failed to create ordinal vector with Xpetra::VectorFactory.");
256  for(int i = 0; i < int(numGlobalIndices); i++)
257  {
258  loVec->replaceGlobalValue(i, 0, array[i]);
259  }
260  return loVec;
261 }
262 
263 template<>
264 RCP<Tpetra_MultiVector_double> loadDataFromMatlab<RCP<Tpetra_MultiVector_double>>(const mxArray* mxa)
265 {
266  RCP<Tpetra::MultiVector<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> mv;
267  try
268  {
269  int nr = mxGetM(mxa);
270  int nc = mxGetN(mxa);
271  double* pr = mxGetPr(mxa);
272  RCP<const Teuchos::Comm<int>> comm = Tpetra::DefaultPlatform::getDefaultPlatform().getComm();
273  //numGlobalIndices for map constructor is the number of rows in matrix/vectors, right?
274  RCP<const muemex_map_type> map = rcp(new muemex_map_type(nr, (mm_GlobalOrd) 0, comm));
275  //Allocate a new array of complex values to use with the multivector
276  Teuchos::ArrayView<const double> arrView(pr, nr * nc);
277  mv = rcp(new Tpetra::MultiVector<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>(map, arrView, size_t(nr), size_t(nc)));
278  }
279  catch(std::exception& e)
280  {
281  mexPrintf("Error constructing Tpetra MultiVector.\n");
282  std::cout << e.what() << std::endl;
283  }
284  return mv;
285 }
286 
287 template<>
288 RCP<Tpetra_MultiVector_complex> loadDataFromMatlab<RCP<Tpetra_MultiVector_complex>>(const mxArray* mxa)
289 {
290  RCP<Tpetra::MultiVector<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> mv;
291  try
292  {
293  int nr = mxGetM(mxa);
294  int nc = mxGetN(mxa);
295  double* pr = mxGetPr(mxa);
296  double* pi = mxGetPi(mxa);
297  RCP<const Teuchos::Comm<int>> comm = Tpetra::DefaultPlatform::getDefaultPlatform().getComm();
298  //numGlobalIndices for map constructor is the number of rows in matrix/vectors, right?
299  RCP<const muemex_map_type> map = rcp(new muemex_map_type(nr, (mm_GlobalOrd) 0, comm));
300  //Allocate a new array of complex values to use with the multivector
301  complex_t* myArr = new complex_t[nr * nc];
302  for(int n = 0; n < nc; n++)
303  {
304  for(int m = 0; m < nr; m++)
305  {
306  myArr[n * nr + m] = complex_t(pr[n * nr + m], pi[n * nr + m]);
307  }
308  }
309  Teuchos::ArrayView<complex_t> arrView(myArr, nr * nc);
310  mv = rcp(new Tpetra::MultiVector<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>(map, arrView, nr, nc));
311  }
312  catch(std::exception& e)
313  {
314  mexPrintf("Error constructing Tpetra MultiVector.\n");
315  std::cout << e.what() << std::endl;
316  }
317  return mv;
318 }
319 
320 template<>
321 RCP<Tpetra_CrsMatrix_double> loadDataFromMatlab<RCP<Tpetra_CrsMatrix_double>>(const mxArray* mxa)
322 {
323  bool success = false;
324  RCP<Tpetra_CrsMatrix_double> A;
325 
326  int* colptr = NULL;
327  int* rowind = NULL;
328 
329  try
330  {
331  RCP<const Teuchos::Comm<int>> comm = rcp(new Teuchos::SerialComm<int>());
332  //numGlobalIndices is just the number of rows in the matrix
333  const Tpetra::global_size_t numGlobalIndices = mxGetM(mxa);
334  const mm_GlobalOrd indexBase = 0;
335  RCP<const muemex_map_type> rowMap = rcp(new muemex_map_type(numGlobalIndices, indexBase, comm));
336  RCP<const muemex_map_type> domainMap = rcp(new muemex_map_type(mxGetN(mxa), indexBase, comm));
337  A = Tpetra::createCrsMatrix<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>(rowMap);
338  double* valueArray = mxGetPr(mxa);
339  int nc = mxGetN(mxa);
340  if(rewrap_ints)
341  {
342  //mwIndex_to_int allocates memory so must delete[] later
343  colptr = mwIndex_to_int(nc + 1, mxGetJc(mxa));
344  rowind = mwIndex_to_int(colptr[nc], mxGetIr(mxa));
345  }
346  else
347  {
348  rowind = (int*) mxGetIr(mxa);
349  colptr = (int*) mxGetJc(mxa);
350  }
351  for(int i = 0; i < nc; i++)
352  {
353  for(int j = colptr[i]; j < colptr[i + 1]; j++)
354  {
355  //'array' of 1 element, containing column (in global matrix).
356  Teuchos::ArrayView<mm_GlobalOrd> cols = Teuchos::ArrayView<mm_GlobalOrd>(&i, 1);
357  //'array' of 1 element, containing value
358  Teuchos::ArrayView<double> vals = Teuchos::ArrayView<double>(&valueArray[j], 1);
359  A->insertGlobalValues(rowind[j], cols, vals);
360  }
361  }
362  A->fillComplete(domainMap, rowMap);
363  if(rewrap_ints)
364  {
365  delete[] rowind; rowind = NULL;
366  delete[] colptr; colptr = NULL;
367  }
368  success = true;
369  }
370  catch(std::exception& e)
371  {
372  if(rewrap_ints)
373  {
374  if(rowind!=NULL) delete[] rowind;
375  if(colptr!=NULL) delete[] colptr;
376  rowind = NULL;
377  colptr = NULL;
378  }
379  mexPrintf("Error while constructing Tpetra matrix:\n");
380  std::cout << e.what() << std::endl;
381  }
382  if(!success)
383  mexErrMsgTxt("An error occurred while setting up a Tpetra matrix.\n");
384  return A;
385 }
386 
387 template<>
388 RCP<Tpetra_CrsMatrix_complex> loadDataFromMatlab<RCP<Tpetra_CrsMatrix_complex>>(const mxArray* mxa)
389 {
390  RCP<Tpetra_CrsMatrix_complex> A;
391  //Create a map in order to create the matrix (taken from muelu basic example - complex)
392  try
393  {
394  RCP<const Teuchos::Comm<int>> comm = Tpetra::DefaultPlatform::getDefaultPlatform().getComm();
395  const Tpetra::global_size_t numGlobalIndices = mxGetM(mxa);
396  const mm_GlobalOrd indexBase = 0;
397  RCP<const muemex_map_type> rowMap = rcp(new muemex_map_type(numGlobalIndices, indexBase, comm));
398  RCP<const muemex_map_type> domainMap = rcp(new muemex_map_type(mxGetN(mxa), indexBase, comm));
399  A = Tpetra::createCrsMatrix<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>(rowMap);
400  double* realArray = mxGetPr(mxa);
401  double* imagArray = mxGetPi(mxa);
402  int* colptr;
403  int* rowind;
404  int nc = mxGetN(mxa);
405  if(rewrap_ints)
406  {
407  //mwIndex_to_int allocates memory so must delete[] later
408  colptr = mwIndex_to_int(nc + 1, mxGetJc(mxa));
409  rowind = mwIndex_to_int(colptr[nc], mxGetIr(mxa));
410  }
411  else
412  {
413  rowind = (int*) mxGetIr(mxa);
414  colptr = (int*) mxGetJc(mxa);
415  }
416  for(int i = 0; i < nc; i++)
417  {
418  for(int j = colptr[i]; j < colptr[i + 1]; j++)
419  {
420  //here assuming that complex_t will always be defined as std::complex<double>
421  //use 'value' over and over again with Teuchos::ArrayViews to insert into matrix
422  complex_t value = std::complex<double>(realArray[j], imagArray[j]);
423  Teuchos::ArrayView<mm_GlobalOrd> cols = Teuchos::ArrayView<mm_GlobalOrd>(&i, 1);
424  Teuchos::ArrayView<complex_t> vals = Teuchos::ArrayView<complex_t>(&value, 1);
425  A->insertGlobalValues(rowind[j], cols, vals);
426  }
427  }
428  A->fillComplete(domainMap, rowMap);
429  if(rewrap_ints)
430  {
431  delete[] rowind;
432  delete[] colptr;
433  }
434  }
435  catch(std::exception& e)
436  {
437  mexPrintf("Error while constructing tpetra matrix:\n");
438  std::cout << e.what() << std::endl;
439  }
440  return A;
441 }
442 
443 template<>
444 RCP<Xpetra::Matrix<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> loadDataFromMatlab<RCP<Xpetra::Matrix<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>>>(const mxArray* mxa)
445 {
446  RCP<Tpetra::CrsMatrix<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> tmat = loadDataFromMatlab<RCP<Tpetra::CrsMatrix<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>>>(mxa);
447  return MueLu::TpetraCrs_To_XpetraMatrix<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>(tmat);
448 }
449 
450 template<>
451 RCP<Xpetra::Matrix<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> loadDataFromMatlab<RCP<Xpetra::Matrix<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>>>(const mxArray* mxa)
452 {
453  RCP<Tpetra::CrsMatrix<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> tmat = loadDataFromMatlab<RCP<Tpetra::CrsMatrix<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>>>(mxa);
454  return MueLu::TpetraCrs_To_XpetraMatrix<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>(tmat);
455 }
456 
457 template<>
458 RCP<Xpetra::MultiVector<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> loadDataFromMatlab<RCP<Xpetra::MultiVector<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>>>(const mxArray* mxa)
459 {
460  RCP<Tpetra::MultiVector<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> tpetraMV = loadDataFromMatlab<RCP<Tpetra::MultiVector<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>>>(mxa);
461  return MueLu::TpetraMultiVector_To_XpetraMultiVector<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>(tpetraMV);
462 }
463 
464 template<>
465 RCP<Xpetra::MultiVector<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> loadDataFromMatlab<RCP<Xpetra::MultiVector<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>>>(const mxArray* mxa)
466 {
467  RCP<Tpetra::MultiVector<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> tpetraMV = loadDataFromMatlab<RCP<Tpetra::MultiVector<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>>>(mxa);
468  return MueLu::TpetraMultiVector_To_XpetraMultiVector<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>(tpetraMV);
469 }
470 
471 template<>
472 RCP<Epetra_CrsMatrix> loadDataFromMatlab<RCP<Epetra_CrsMatrix>>(const mxArray* mxa)
473 {
474  RCP<Epetra_CrsMatrix> matrix;
475  try
476  {
477  int* colptr;
478  int* rowind;
479  double* vals = mxGetPr(mxa);
480  int nr = mxGetM(mxa);
481  int nc = mxGetN(mxa);
482  if(rewrap_ints)
483  {
484  colptr = mwIndex_to_int(nc + 1, mxGetJc(mxa));
485  rowind = mwIndex_to_int(colptr[nc], mxGetIr(mxa));
486  }
487  else
488  {
489  rowind = (int*) mxGetIr(mxa);
490  colptr = (int*) mxGetJc(mxa);
491  }
492  Epetra_SerialComm Comm;
493  Epetra_Map RangeMap(nr, 0, Comm);
494  Epetra_Map DomainMap(nc, 0, Comm);
495  matrix = rcp(new Epetra_CrsMatrix(Epetra_DataAccess::Copy, RangeMap, DomainMap, 0));
496  /* Do the matrix assembly */
497  for(int i = 0; i < nc; i++)
498  {
499  for(int j = colptr[i]; j < colptr[i + 1]; j++)
500  {
501  //global row, # of entries, value array, column indices array
502  matrix->InsertGlobalValues(rowind[j], 1, &vals[j], &i);
503  }
504  }
505  matrix->FillComplete(DomainMap, RangeMap);
506  if(rewrap_ints)
507  {
508  delete [] rowind;
509  delete [] colptr;
510  }
511  }
512  catch(std::exception& e)
513  {
514  mexPrintf("An error occurred while setting up an Epetra matrix:\n");
515  std::cout << e.what() << std::endl;
516  }
517  return matrix;
518 }
519 
520 template<>
521 RCP<Epetra_MultiVector> loadDataFromMatlab<RCP<Epetra_MultiVector>>(const mxArray* mxa)
522 {
523  int nr = mxGetM(mxa);
524  int nc = mxGetN(mxa);
525  Epetra_SerialComm Comm;
526  Epetra_BlockMap map(nr * nc, 1, 0, Comm);
527  return rcp(new Epetra_MultiVector(Epetra_DataAccess::Copy, map, mxGetPr(mxa), nr, nc));
528 }
529 
530 template<>
531 RCP<MAggregates> loadDataFromMatlab<RCP<MAggregates>>(const mxArray* mxa)
532 {
533  if(mxGetNumberOfElements(mxa) != 1)
534  throw runtime_error("Aggregates must be individual structs in MATLAB.");
535  if(!mxIsStruct(mxa))
536  throw runtime_error("Trying to pull aggregates from non-struct MATLAB object.");
537  //assume that in matlab aggregate structs will only be stored in a 1x1 array
538  //mxa must have the same fields as the ones declared in constructAggregates function in muelu.m for this to work
539  const int correctNumFields = 5; //change if more fields are added to the aggregates representation in constructAggregates in muelu.m
540  if(mxGetNumberOfFields(mxa) != correctNumFields)
541  throw runtime_error("Aggregates structure has wrong number of fields.");
542  //Pull MuemexData types back out
543  int nVert = *(int*) mxGetData(mxGetField(mxa, 0, "nVertices"));
544  int nAgg = *(int*) mxGetData(mxGetField(mxa, 0, "nAggregates"));
545  //Now have all the data needed to fully reconstruct the aggregate
546  //Use similar approach as UserAggregationFactory (which is written for >1 thread but will just be serial here)
547  RCP<const Teuchos::Comm<int>> comm = Teuchos::DefaultComm<int>::getComm();
548  int myRank = comm->getRank();
549  Xpetra::UnderlyingLib lib = Xpetra::UseTpetra;
550  RCP<Xpetra::Map<mm_LocalOrd, mm_GlobalOrd, mm_node_t>> map = Xpetra::MapFactory<mm_LocalOrd, mm_GlobalOrd, mm_node_t>::Build(lib, nVert, 0, comm);
551  RCP<MAggregates> agg = rcp(new MAggregates(map));
552  agg->SetNumAggregates(nAgg);
553  //Get handles for the vertex2AggId and procwinner arrays in reconstituted aggregates object
554  //this is serial so all procwinner values will be same (0)
555  ArrayRCP<mm_LocalOrd> vertex2AggId = agg->GetVertex2AggId()->getDataNonConst(0); //the '0' means first (and only) column of multivector, since is just vector
556  ArrayRCP<mm_LocalOrd> procWinner = agg->GetProcWinner()->getDataNonConst(0);
557  //mm_LocalOrd and int are equivalent, so is ok to talk about aggSize with just 'int'
558  //Deep copy the entire vertex2AggID and isRoot arrays, which are both nVert items long
559  //At the same time, set ProcWinner
560  mxArray* vertToAggID_in = mxGetField(mxa, 0, "vertexToAggID");
561  int* vertToAggID_inArray = (int*) mxGetData(vertToAggID_in);
562  mxArray* rootNodes_in = mxGetField(mxa, 0, "rootNodes");
563  int* rootNodes_inArray = (int*) mxGetData(rootNodes_in);
564  for(int i = 0; i < nVert; i++)
565  {
566  vertex2AggId[i] = vertToAggID_inArray[i];
567  procWinner[i] = myRank; //all nodes are going to be on the same proc
568  agg->SetIsRoot(i, false); //the ones that are root will be set in next loop
569  }
570  for(int i = 0; i < nAgg; i++) //rootNodesToCopy is an array of node IDs which are the roots of their aggs
571  {
572  agg->SetIsRoot(rootNodes_inArray[i], true);
573  }
574  //Now recompute the aggSize array and cache the results in the object
575  agg->ComputeAggregateSizes(true, true);
576  agg->AggregatesCrossProcessors(false);
577  return agg;
578 }
579 
580 template<>
581 RCP<MAmalInfo> loadDataFromMatlab<RCP<MAmalInfo>>(const mxArray* mxa)
582 {
583  RCP<MAmalInfo> amal;
584  throw runtime_error("AmalgamationInfo not supported in Muemex yet.");
585  return amal;
586 }
587 
588 template<>
589 RCP<MGraph> loadDataFromMatlab<RCP<MGraph>>(const mxArray* mxa)
590 {
591  //mxa must be struct with logical sparse matrix called 'edges' and Nx1 int32 array 'boundaryNodes'
592  mxArray* edges = mxGetField(mxa, 0, "edges");
593  mxArray* boundaryNodes = mxGetField(mxa, 0, "boundaryNodes");
594  if(edges == NULL)
595  throw runtime_error("Graph structure in MATLAB must have a field called 'edges' (logical sparse matrix)");
596  if(boundaryNodes == NULL)
597  throw runtime_error("Graph structure in MATLAB must have a field called 'boundaryNodes' (int32 array containing list of boundary nodes)");
598  int* boundaryList = (int*) mxGetData(boundaryNodes);
599  if(!mxIsSparse(edges) || mxGetClassID(edges) != mxLOGICAL_CLASS)
600  throw runtime_error("Graph edges must be stored as a logical sparse matrix.");
601  // Note that Matlab stores sparse matrices in column major format.
602  mwIndex* matlabColPtrs = mxGetJc(edges);
603  mwIndex* matlabRowIndices = mxGetIr(edges);
604  mm_GlobalOrd nRows = (mm_GlobalOrd) mxGetM(edges);
605 
606  // Create and populate row-major CRS data structures for Xpetra::TpetraCrsGraph.
607 
608  // calculate number of nonzeros in each row
609  Teuchos::Array<int> entriesPerRow(nRows);
610  int nnz = matlabColPtrs[mxGetN(edges)]; //last entry in matlabColPtrs
611  for(int i = 0; i < nnz; i++)
612  entriesPerRow[matlabRowIndices[i]]++;
613  // Populate usual row index array. We don't need this for the Xpetra Graph ctor, but
614  // it's convenient for building up the column index array, which the ctor does need.
615  Teuchos::Array<int> rows(nRows+1);
616  rows[0] = 0;
617  for(int i = 0; i < nRows; i++)
618  rows[i+1] = rows[i] + entriesPerRow[i];
619  Teuchos::Array<int> cols(nnz); //column index array
620  Teuchos::Array<int> insertionsPerRow(nRows,0); //track of #insertions done per row
621  int ncols = mxGetN(edges);
622  for (int colNum=0; colNum<ncols; ++colNum) {
623  int ci = matlabColPtrs[colNum];
624  for (int j=ci; j<Teuchos::as<int>(matlabColPtrs[colNum+1]); ++j) {
625  int rowNum = matlabRowIndices[j];
626  cols[ rows[rowNum] + insertionsPerRow[rowNum] ] = colNum;
627  insertionsPerRow[rowNum]++;
628  }
629  }
630  //Find maximum
631  int maxNzPerRow = 0;
632  for(int i = 0; i < nRows; i++) {
633  if(maxNzPerRow < entriesPerRow[i])
634  maxNzPerRow = entriesPerRow[i];
635  }
636 
637  RCP<const Teuchos::Comm<mm_GlobalOrd>> comm = rcp(new Teuchos::SerialComm<mm_GlobalOrd>());
638  typedef Xpetra::TpetraMap<mm_LocalOrd, mm_GlobalOrd, mm_node_t> MMap;
639  RCP<MMap> map = rcp(new MMap(nRows, 0, comm));
640  typedef Xpetra::TpetraCrsGraph<mm_LocalOrd, mm_GlobalOrd, mm_node_t> TpetraGraph;
641  RCP<TpetraGraph> tgraph = rcp(new TpetraGraph(map, (size_t) maxNzPerRow));
642  //Populate tgraph in compressed-row format. Must get each row individually...
643  for(int i = 0; i < nRows; ++i) {
644  tgraph->insertGlobalIndices((mm_GlobalOrd) i, cols(rows[i],entriesPerRow[i]));
645  }
646  tgraph->fillComplete(map, map);
647  RCP<MGraph> mgraph = rcp(new MueLu::Graph<mm_LocalOrd, mm_GlobalOrd, mm_node_t>(tgraph));
648  //Set boundary nodes
649  int numBoundaryNodes = mxGetNumberOfElements(boundaryNodes);
650  bool* boundaryFlags = new bool[nRows];
651  for(int i = 0; i < nRows; i++)
652  {
653  boundaryFlags[i] = false;
654  }
655  for(int i = 0; i < numBoundaryNodes; i++)
656  {
657  boundaryFlags[boundaryList[i]] = true;
658  }
659  ArrayRCP<bool> boundaryNodesInput(boundaryFlags, 0, nRows, true);
660  mgraph->SetBoundaryNodeMap(boundaryNodesInput);
661  return mgraph;
662 }
663 
664 
665 #ifdef HAVE_MUELU_INTREPID2
666 template<>
667 RCP<FieldContainer_ordinal> loadDataFromMatlab<RCP<FieldContainer_ordinal>>(const mxArray* mxa)
668 {
669  if(mxGetClassID(mxa) != mxINT32_CLASS)
670  throw runtime_error("FieldContainer must have integer storage entries");
671 
672  int *data = (int *) mxGetData(mxa);
673  int nr = mxGetM(mxa);
674  int nc = mxGetN(mxa);
675 
676 #ifdef HAVE_MUELU_INTREPID2_REFACTOR
677  RCP<FieldContainer_ordinal> fc = rcp(new FieldContainer_ordinal("FC from Matlab",nr,nc));
678 #else
679  RCP<FieldContainer_ordinal> fc = rcp(new FieldContainer_ordinal(nr,nc));
680 #endif
681  for(int col = 0; col < nc; col++)
682  {
683  for(int row = 0; row < nr; row++)
684  {
685  (*fc)(row,col) = data[col * nr + row];
686  }
687  }
688  return fc;
689 }
690 #endif
691 
692 /* ******************************* */
693 /* saveDataToMatlab */
694 /* ******************************* */
695 
696 template<>
697 mxArray* saveDataToMatlab(int& data)
698 {
699  mwSize dims[] = {1, 1};
700  mxArray* mxa = mxCreateNumericArray(2, dims, mxINT32_CLASS, mxREAL);
701  *((int*) mxGetData(mxa)) = data;
702  return mxa;
703 }
704 
705 template<>
706 mxArray* saveDataToMatlab(bool& data)
707 {
708  mwSize dims[] = {1, 1};
709  mxArray* mxa = mxCreateLogicalArray(2, dims);
710  *((bool*) mxGetData(mxa)) = data;
711  return mxa;
712 }
713 
714 template<>
715 mxArray* saveDataToMatlab(double& data)
716 {
717  return mxCreateDoubleScalar(data);
718 }
719 
720 template<>
722 {
723  mwSize dims[] = {1, 1};
724  mxArray* mxa = mxCreateNumericArray(2, dims, mxDOUBLE_CLASS, mxCOMPLEX);
725  *((double*) mxGetPr(mxa)) = real<double>(data);
726  *((double*) mxGetPi(mxa)) = imag<double>(data);
727  return mxa;
728 }
729 
730 template<>
731 mxArray* saveDataToMatlab(string& data)
732 {
733  return mxCreateString(data.c_str());
734 }
735 
736 template<>
737 mxArray* saveDataToMatlab(RCP<Xpetra_map>& data)
738 {
739  //Precondition: Memory has already been allocated by MATLAB for the array.
740  int nc = data->getGlobalNumElements();
741  int nr = 1;
742  mxArray* output = createMatlabMultiVector<double>(nr, nc);
743  double* array = (double*) malloc(sizeof(double) * nr * nc);
744  for(int col = 0; col < nc; col++)
745  {
746  mm_GlobalOrd gid = data->getGlobalElement(col);
747  array[col] = Teuchos::as<double>(gid);
748  }
749  fillMatlabArray<double>(array, output, nc * nr);
750  free(array);
751  return output;
752 }
753 
754 template<>
755 mxArray* saveDataToMatlab(RCP<Xpetra_ordinal_vector>& data)
756 {
757  mwSize len = data->getGlobalLength();
758  //create a single column vector
759  mwSize dimensions[] = {len, 1};
760  mxArray* rv = mxCreateNumericArray(2, dimensions, mxINT32_CLASS, mxREAL);
761  int* dataPtr = (int*) mxGetData(rv);
762  ArrayRCP<const mm_LocalOrd> arr = data->getData(0);
763  for(int i = 0; i < int(data->getGlobalLength()); i++)
764  {
765  dataPtr[i] = arr[i];
766  }
767  return rv;
768 }
769 
770 template<>
771 mxArray* saveDataToMatlab(RCP<Tpetra::MultiVector<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>>& data)
772 {
773  RCP<Xpetra_MultiVector_double> xmv = MueLu::TpetraMultiVector_To_XpetraMultiVector(data);
774  return saveDataToMatlab(xmv);
775 }
776 
777 template<>
778 mxArray* saveDataToMatlab(RCP<Tpetra::MultiVector<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>>& data)
779 {
780  RCP<Xpetra_MultiVector_complex> xmv = MueLu::TpetraMultiVector_To_XpetraMultiVector(data);
781  return saveDataToMatlab(xmv);
782 }
783 
784 template<>
785 mxArray* saveDataToMatlab(RCP<Tpetra_CrsMatrix_double>& data)
786 {
787  RCP<Xpetra::Matrix<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> xmat = TpetraCrs_To_XpetraMatrix(data);
788  return saveDataToMatlab(xmat);
789 }
790 
791 template<>
792 mxArray* saveDataToMatlab(RCP<Tpetra_CrsMatrix_complex>& data)
793 {
794  RCP<Xpetra::Matrix<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> xmat = TpetraCrs_To_XpetraMatrix(data);
795  return saveDataToMatlab(xmat);
796 }
797 
798 template<>
799 mxArray* saveDataToMatlab(RCP<Xpetra_Matrix_double>& data)
800 {
801  typedef double Scalar;
802  int nr = data->getGlobalNumRows();
803  int nc = data->getGlobalNumCols();
804  int nnz = data->getGlobalNumEntries();
805 
806  if(nnz==-1) nnz=data->getNodeNumEntries(); // Workaround for global constants stuff.
807 #ifdef VERBOSE_OUTPUT
808  RCP<Teuchos::FancyOStream> fancyStream = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
809  mat->describe(*fancyStream, Teuchos::VERB_EXTREME);
810 #endif
811  mxArray* mxa = createMatlabSparse<Scalar>(nr, nc, nnz);
812  mwIndex* ir = mxGetIr(mxa);
813  mwIndex* jc = mxGetJc(mxa);
814  for(int i = 0; i < nc + 1; i++)
815  {
816  jc[i] = 0;
817  }
818 
819  size_t maxEntriesPerRow = data->getGlobalMaxNumRowEntries();
820  if(maxEntriesPerRow == Teuchos::OrdinalTraits<size_t>::invalid() || maxEntriesPerRow == 0) maxEntriesPerRow = data->getNodeMaxNumRowEntries();
821 
822  int* rowProgress = new int[nc];
823  //The array that will be copied to Pr and (if complex) Pi later
824  Scalar* sparseVals = new Scalar[nnz];
825  size_t numEntries;
826  if(data->isLocallyIndexed())
827  {
828  Scalar* rowValArray = new Scalar[maxEntriesPerRow];
829  Teuchos::ArrayView<Scalar> rowVals(rowValArray, maxEntriesPerRow);
830  mm_LocalOrd* rowIndicesArray = new mm_LocalOrd[maxEntriesPerRow];
831  Teuchos::ArrayView<mm_LocalOrd> rowIndices(rowIndicesArray, maxEntriesPerRow);
832  for(mm_LocalOrd m = 0; m < nr; m++) //All rows in the Xpetra matrix
833  {
834  data->getLocalRowCopy(m, rowIndices, rowVals, numEntries); //Get the row
835  for(mm_LocalOrd entry = 0; entry < int(numEntries); entry++) //All entries in row
836  {
837  jc[rowIndices[entry] + 1]++; //for each entry, increase jc for the entry's column
838  }
839  }
840 
841  //now jc holds the number of elements in each column, but needs cumulative sum over all previous columns also
842  int entriesAccum = 0;
843  for(int n = 0; n <= nc; n++)
844  {
845  int temp = entriesAccum;
846  entriesAccum += jc[n];
847  jc[n] += temp;
848  }
849  //Jc now populated with colptrs
850  for(int i = 0; i < nc; i++)
851  {
852  rowProgress[i] = 0;
853  }
854  //Row progress values like jc but keep track as the MATLAB matrix is being filled in
855  for(mm_LocalOrd m = 0; m < nr; m++) //rows
856  {
857  data->getLocalRowCopy(m, rowIndices, rowVals, numEntries);
858  for(mm_LocalOrd i = 0; i < int(numEntries); i++) //entries in row m (NOT columns)
859  {
860  //row is m, col is rowIndices[i], val is rowVals[i]
861  mm_LocalOrd col = rowIndices[i];
862  sparseVals[jc[col] + rowProgress[col]] = rowVals[i]; //Set value
863  ir[jc[col] + rowProgress[col]] = m; //Set row at which value occurs
864  rowProgress[col]++;
865  }
866  }
867  delete[] rowIndicesArray;
868  }
869  else
870  {
871  Teuchos::ArrayView<const mm_GlobalOrd> rowIndices;
872  Teuchos::ArrayView<const Scalar> rowVals;
873  for(mm_GlobalOrd m = 0; m < nr; m++)
874  {
875  data->getGlobalRowView(m, rowIndices, rowVals);
876  for(mm_GlobalOrd n = 0; n < rowIndices.size(); n++)
877  {
878  jc[rowIndices[n] + 1]++;
879  }
880  }
881  //Last element of jc is just nnz
882  jc[nc] = nnz;
883  //Jc now populated with colptrs
884  for(int i = 0; i < nc; i++)
885  {
886  rowProgress[i] = 0;
887  }
888  int entriesAccum = 0;
889  for(int n = 0; n <= nc; n++)
890  {
891  int temp = entriesAccum;
892  entriesAccum += jc[n];
893  jc[n] += temp;
894  }
895  //Row progress values like jc but keep track as the MATLAB matrix is being filled in
896  for(mm_GlobalOrd m = 0; m < nr; m++) //rows
897  {
898  data->getGlobalRowView(m, rowIndices, rowVals);
899  for(mm_LocalOrd i = 0; i < rowIndices.size(); i++) //entries in row m
900  {
901  mm_GlobalOrd col = rowIndices[i]; //row is m, col is rowIndices[i], val is rowVals[i]
902  sparseVals[jc[col] + rowProgress[col]] = rowVals[i]; //Set value
903  ir[jc[col] + rowProgress[col]] = m; //Set row at which value occurs
904  rowProgress[col]++;
905  }
906  }
907  }
908  //finally, copy sparseVals into pr (and pi, if complex)
909  fillMatlabArray<Scalar>(sparseVals, mxa, nnz);
910  delete[] sparseVals;
911  delete[] rowProgress;
912  return mxa;
913 }
914 
915 template<>
916 mxArray* saveDataToMatlab(RCP<Xpetra_Matrix_complex>& data)
917 {
918  typedef complex_t Scalar;
919  int nr = data->getGlobalNumRows();
920  int nc = data->getGlobalNumCols();
921  int nnz = data->getGlobalNumEntries();
922 #ifdef VERBOSE_OUTPUT
923  RCP<Teuchos::FancyOStream> fancyStream = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
924  mat->describe(*fancyStream, Teuchos::VERB_EXTREME);
925 #endif
926  mxArray* mxa = createMatlabSparse<Scalar>(nr, nc, nnz);
927  mwIndex* ir = mxGetIr(mxa);
928  mwIndex* jc = mxGetJc(mxa);
929  for(int i = 0; i < nc + 1; i++)
930  {
931  jc[i] = 0;
932  }
933  size_t maxEntriesPerRow = data->getGlobalMaxNumRowEntries();
934  int* rowProgress = new int[nc];
935  //The array that will be copied to Pr and (if complex) Pi later
936  Scalar* sparseVals = new Scalar[nnz];
937  size_t numEntries;
938  if(data->isLocallyIndexed())
939  {
940  Scalar* rowValArray = new Scalar[maxEntriesPerRow];
941  Teuchos::ArrayView<Scalar> rowVals(rowValArray, maxEntriesPerRow);
942  mm_LocalOrd* rowIndicesArray = new mm_LocalOrd[maxEntriesPerRow];
943  Teuchos::ArrayView<mm_LocalOrd> rowIndices(rowIndicesArray, maxEntriesPerRow);
944  for(mm_LocalOrd m = 0; m < nr; m++) //All rows in the Xpetra matrix
945  {
946  data->getLocalRowCopy(m, rowIndices, rowVals, numEntries); //Get the row
947  for(mm_LocalOrd entry = 0; entry < int(numEntries); entry++) //All entries in row
948  {
949  jc[rowIndices[entry] + 1]++; //for each entry, increase jc for the entry's column
950  }
951  }
952  //now jc holds the number of elements in each column, but needs cumulative sum over all previous columns also
953  int entriesAccum = 0;
954  for(int n = 0; n <= nc; n++)
955  {
956  int temp = entriesAccum;
957  entriesAccum += jc[n];
958  jc[n] += temp;
959  }
960  //Jc now populated with colptrs
961  for(int i = 0; i < nc; i++)
962  {
963  rowProgress[i] = 0;
964  }
965  //Row progress values like jc but keep track as the MATLAB matrix is being filled in
966  for(mm_LocalOrd m = 0; m < nr; m++) //rows
967  {
968  data->getLocalRowCopy(m, rowIndices, rowVals, numEntries);
969  for(mm_LocalOrd i = 0; i < int(numEntries); i++) //entries in row m (NOT columns)
970  {
971  //row is m, col is rowIndices[i], val is rowVals[i]
972  mm_LocalOrd col = rowIndices[i];
973  sparseVals[jc[col] + rowProgress[col]] = rowVals[i]; //Set value
974  ir[jc[col] + rowProgress[col]] = m; //Set row at which value occurs
975  rowProgress[col]++;
976  }
977  }
978  delete[] rowIndicesArray;
979  }
980  else
981  {
982  Teuchos::ArrayView<const mm_GlobalOrd> rowIndices;
983  Teuchos::ArrayView<const Scalar> rowVals;
984  for(mm_GlobalOrd m = 0; m < nr; m++)
985  {
986  data->getGlobalRowView(m, rowIndices, rowVals);
987  for(mm_GlobalOrd n = 0; n < rowIndices.size(); n++)
988  {
989  jc[rowIndices[n] + 1]++;
990  }
991  }
992  //Last element of jc is just nnz
993  jc[nc] = nnz;
994  //Jc now populated with colptrs
995  for(int i = 0; i < nc; i++)
996  {
997  rowProgress[i] = 0;
998  }
999  int entriesAccum = 0;
1000  for(int n = 0; n <= nc; n++)
1001  {
1002  int temp = entriesAccum;
1003  entriesAccum += jc[n];
1004  jc[n] += temp;
1005  }
1006  //Row progress values like jc but keep track as the MATLAB matrix is being filled in
1007  for(mm_GlobalOrd m = 0; m < nr; m++) //rows
1008  {
1009  data->getGlobalRowView(m, rowIndices, rowVals);
1010  for(mm_LocalOrd i = 0; i < rowIndices.size(); i++) //entries in row m
1011  {
1012  mm_GlobalOrd col = rowIndices[i]; //row is m, col is rowIndices[i], val is rowVals[i]
1013  sparseVals[jc[col] + rowProgress[col]] = rowVals[i]; //Set value
1014  ir[jc[col] + rowProgress[col]] = m; //Set row at which value occurs
1015  rowProgress[col]++;
1016  }
1017  }
1018  }
1019  //finally, copy sparseVals into pr (and pi, if complex)
1020  fillMatlabArray<Scalar>(sparseVals, mxa, nnz);
1021  delete[] sparseVals;
1022  delete[] rowProgress;
1023  return mxa;
1024 }
1025 
1026 /*
1027 template<>
1028 mxArray* saveDataToMatlab(RCP<Xpetra::MultiVector<Scalar, mm_LocalOrd, mm_GlobalOrd, mm_node_t>>& data)
1029 {
1030  //Precondition: Memory has already been allocated by MATLAB for the array.
1031  int nr = data->getGlobalLength();
1032  int nc = data->getNumVectors();
1033  mxArray* output = createMatlabMultiVector<Scalar>(nr, nc);
1034  Scalar* array = (Scalar*) malloc(sizeof(Scalar) * nr * nc);
1035  for(int col = 0; col < nc; col++)
1036  {
1037  Teuchos::ArrayRCP<const Scalar> colData = data->getData(col);
1038  for(int row = 0; row < nr; row++)
1039  {
1040  array[col * nr + row] = colData[row];
1041  }
1042  }
1043  fillMatlabArray<Scalar>(array, output, nc * nr);
1044  free(array);
1045  return output;
1046 }
1047 */
1048 
1049 template<>
1050 mxArray* saveDataToMatlab(RCP<Xpetra::MultiVector<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>>& data)
1051 {
1052  //Precondition: Memory has already been allocated by MATLAB for the array.
1053  int nr = data->getGlobalLength();
1054  int nc = data->getNumVectors();
1055  mxArray* output = createMatlabMultiVector<double>(nr, nc);
1056  double* array = (double*) malloc(sizeof(double) * nr * nc);
1057  for(int col = 0; col < nc; col++)
1058  {
1059  Teuchos::ArrayRCP<const double> colData = data->getData(col);
1060  for(int row = 0; row < nr; row++)
1061  {
1062  array[col * nr + row] = colData[row];
1063  }
1064  }
1065  fillMatlabArray<double>(array, output, nc * nr);
1066  free(array);
1067  return output;
1068 }
1069 
1070 template<>
1071 mxArray* saveDataToMatlab(RCP<Xpetra::MultiVector<complex_t, mm_LocalOrd, mm_GlobalOrd, mm_node_t>>& data)
1072 {
1073  //Precondition: Memory has already been allocated by MATLAB for the array.
1074  int nr = data->getGlobalLength();
1075  int nc = data->getNumVectors();
1076  mxArray* output = createMatlabMultiVector<complex_t>(nr, nc);
1077  complex_t* array = (complex_t*) malloc(sizeof(complex_t) * nr * nc);
1078  for(int col = 0; col < nc; col++)
1079  {
1080  Teuchos::ArrayRCP<const complex_t> colData = data->getData(col);
1081  for(int row = 0; row < nr; row++)
1082  {
1083  array[col * nr + row] = colData[row];
1084  }
1085  }
1086  fillMatlabArray<complex_t>(array, output, nc * nr);
1087  free(array);
1088  return output;
1089 }
1090 
1091 template<>
1092 mxArray* saveDataToMatlab(RCP<Epetra_CrsMatrix>& data)
1093 {
1094  RCP<Xpetra_Matrix_double> xmat = EpetraCrs_To_XpetraMatrix<double, mm_LocalOrd, mm_GlobalOrd, mm_node_t>(data);
1095  return saveDataToMatlab(xmat);
1096 }
1097 
1098 template<>
1099 mxArray* saveDataToMatlab(RCP<Epetra_MultiVector>& data)
1100 {
1101  mxArray* output = mxCreateDoubleMatrix(data->GlobalLength(), data->NumVectors(), mxREAL);
1102  double* dataPtr = mxGetPr(output);
1103  data->ExtractCopy(dataPtr, data->GlobalLength());
1104  return output;
1105 }
1106 
1107 template<>
1108 mxArray* saveDataToMatlab(RCP<MAggregates>& data)
1109 {
1110  //Set up array of inputs for matlab constructAggregates
1111  int numNodes = data->GetVertex2AggId()->getData(0).size();
1112  int numAggs = data->GetNumAggregates();
1113  mxArray* dataIn[5];
1114  mwSize singleton[] = {1, 1};
1115  dataIn[0] = mxCreateNumericArray(2, singleton, mxINT32_CLASS, mxREAL);
1116  *((int*) mxGetData(dataIn[0])) = numNodes;
1117  dataIn[1] = mxCreateNumericArray(2, singleton, mxINT32_CLASS, mxREAL);
1118  *((int*) mxGetData(dataIn[1])) = numAggs;
1119  mwSize nodeArrayDims[] = {(mwSize) numNodes, 1}; //dimensions for Nx1 array, where N is number of nodes (vert2Agg)
1120  dataIn[2] = mxCreateNumericArray(2, nodeArrayDims, mxINT32_CLASS, mxREAL);
1121  int* vtaid = (int*) mxGetData(dataIn[2]);
1122  ArrayRCP<const mm_LocalOrd> vertexToAggID = data->GetVertex2AggId()->getData(0);
1123  for(int i = 0; i < numNodes; i++)
1124  {
1125  vtaid[i] = vertexToAggID[i];
1126  }
1127  mwSize aggArrayDims[] = {(mwSize) numAggs, 1}; //dims for Nx1 array, where N is number of aggregates (rootNodes, aggSizes)
1128  dataIn[3] = mxCreateNumericArray(2, aggArrayDims, mxINT32_CLASS, mxREAL);
1129  //First, find out if the aggregates even have 1 root node per aggregate. If not, assume roots are invalid and assign ourselves
1130  int totalRoots = 0;
1131  for(int i = 0; i < numNodes; i++)
1132  {
1133  if(data->IsRoot(i))
1134  totalRoots++;
1135  }
1136  bool reassignRoots = false;
1137  if(totalRoots != numAggs)
1138  {
1139  cout << endl << "Warning: Number of root nodes and number of aggregates do not match." << endl;
1140  cout << "Will reassign root nodes when writing aggregates to matlab." << endl << endl;
1141  reassignRoots = true;
1142  }
1143  int* rn = (int*) mxGetData(dataIn[3]); //list of root nodes (in no particular order)
1144  {
1145  if(reassignRoots)
1146  {
1147  //For each aggregate, just pick the first node we see in it and set it as root
1148  int lastFoundNode = 0; //heuristic for speed, a node in aggregate N+1 is likely to come very soon after a node in agg N
1149  for(int i = 0; i < numAggs; i++)
1150  {
1151  rn[i] = -1;
1152  for(int j = lastFoundNode; j < lastFoundNode + numNodes; j++)
1153  {
1154  int index = j % numNodes;
1155  if(vertexToAggID[index] == i)
1156  {
1157  rn[i] = index;
1158  lastFoundNode = index;
1159  }
1160  }
1161  TEUCHOS_TEST_FOR_EXCEPTION(rn[i] == -1, runtime_error, "Invalid aggregates: Couldn't find any node in aggregate #" << i << ".");
1162  }
1163  }
1164  else
1165  {
1166  int i = 0; //iterates over aggregate IDs
1167  for(int j = 0; j < numNodes; j++)
1168  {
1169  if(data->IsRoot(j))
1170  {
1171  if(i == numAggs)
1172  throw runtime_error("Cannot store invalid aggregates in MATLAB - more root nodes than aggregates.");
1173  rn[i] = j; //now we know this won't go out of bounds (rn's underlying matlab array is numAggs in length)
1174  i++;
1175  }
1176  }
1177  if(i + 1 < numAggs)
1178  throw runtime_error("Cannot store invalid aggregates in MATLAB - fewer root nodes than aggregates.");
1179  }
1180  }
1181  dataIn[4] = mxCreateNumericArray(1, aggArrayDims, mxINT32_CLASS, mxREAL);
1182  int* as = (int*) mxGetData(dataIn[4]); //list of aggregate sizes
1183  ArrayRCP<mm_LocalOrd> aggSizes = data->ComputeAggregateSizes();
1184  for(int i = 0; i < numAggs; i++)
1185  {
1186  as[i] = aggSizes[i];
1187  }
1188  mxArray* matlabAggs[1];
1189  int result = mexCallMATLAB(1, matlabAggs, 5, dataIn, "constructAggregates");
1190  if(result != 0)
1191  throw runtime_error("Matlab encountered an error while constructing aggregates struct.");
1192  return matlabAggs[0];
1193 }
1194 
1195 template<>
1196 mxArray* saveDataToMatlab(RCP<MAmalInfo>& data)
1197 {
1198  throw runtime_error("AmalgamationInfo not supported in MueMex yet.");
1199  return mxCreateDoubleScalar(0);
1200 }
1201 
1202 template<>
1203 mxArray* saveDataToMatlab(RCP<MGraph>& data)
1204 {
1205  int numEntries = (int) data->GetGlobalNumEdges();
1206  int numRows = (int) data->GetDomainMap()->getGlobalNumElements(); //assume numRows == numCols
1207  mxArray* mat = mxCreateSparseLogicalMatrix(numRows, numRows, numEntries);
1208  mxLogical* outData = (mxLogical*) mxGetData(mat);
1209  mwIndex* rowInds = mxGetIr(mat);
1210  mwIndex* colPtrs = mxGetJc(mat);
1211  mm_LocalOrd* dataCopy = new mm_LocalOrd[numEntries];
1212  mm_LocalOrd* iter = dataCopy;
1213  int* entriesPerRow = new int[numRows];
1214  int* entriesPerCol = new int[numRows];
1215  for(int i = 0; i < numRows; i++)
1216  {
1217  entriesPerRow[i] = 0;
1218  entriesPerCol[i] = 0;
1219  }
1220  for(int i = 0; i < numRows; i++)
1221  {
1222  ArrayView<const mm_LocalOrd> neighbors = data->getNeighborVertices(i); //neighbors has the column indices for row i
1223  memcpy(iter, neighbors.getRawPtr(), sizeof(mm_LocalOrd) * neighbors.size());
1224  entriesPerRow[i] = neighbors.size();
1225  for(int j = 0; j < neighbors.size(); j++)
1226  {
1227  entriesPerCol[neighbors[j]]++;
1228  }
1229  iter += neighbors.size();
1230  }
1231  mwIndex** rowIndsByColumn = new mwIndex*[numRows]; //rowIndsByColumn[0] points to array of row indices in column 1
1232  mxLogical** valuesByColumn = new mxLogical*[numRows];
1233  int* numEnteredPerCol = new int[numRows];
1234  int accum = 0;
1235  for(int i = 0; i < numRows; i++)
1236  {
1237  rowIndsByColumn[i] = &rowInds[accum];
1238  //cout << "Entries in column " << i << " start at offset " << accum << endl;
1239  valuesByColumn[i] = &outData[accum];
1240  accum += entriesPerCol[i];
1241  if(accum > numEntries)
1242  throw runtime_error("potato");
1243  }
1244  for(int i = 0; i < numRows; i++)
1245  {
1246  numEnteredPerCol[i] = 0; //rowIndsByColumn[n][numEnteredPerCol[n]] gives the next place to put a row index
1247  }
1248  //entriesPerCol now has Jc information (col offsets)
1249  accum = 0; //keep track of cumulative index in dataCopy
1250  for(int row = 0; row < numRows; row++)
1251  {
1252  for(int entryInRow = 0; entryInRow < entriesPerRow[row]; entryInRow++)
1253  {
1254  int col = dataCopy[accum];
1255  accum++;
1256  rowIndsByColumn[col][numEnteredPerCol[col]] = row;
1257  valuesByColumn[col][numEnteredPerCol[col]] = (mxLogical) 1;
1258  numEnteredPerCol[col]++;
1259  }
1260  }
1261  accum = 0; //keep track of total entries over all columns
1262  for(int col = 0; col < numRows; col++)
1263  {
1264  colPtrs[col] = accum;
1265  accum += entriesPerCol[col];
1266  }
1267  colPtrs[numRows] = accum; //the last entry in jc, which is equivalent to numEntries
1268  delete[] numEnteredPerCol;
1269  delete[] rowIndsByColumn;
1270  delete[] valuesByColumn;
1271  delete[] dataCopy;
1272  delete[] entriesPerRow;
1273  delete[] entriesPerCol;
1274  //Construct list of boundary nodes
1275  const ArrayRCP<const bool> boundaryFlags = data->GetBoundaryNodeMap();
1276  int numBoundaryNodes = 0;
1277  for(int i = 0; i < boundaryFlags.size(); i++)
1278  {
1279  if(boundaryFlags[i])
1280  numBoundaryNodes++;
1281  }
1282  cout << "Graph has " << numBoundaryNodes << " Dirichlet boundary nodes." << endl;
1283  mwSize dims[] = {(mwSize) numBoundaryNodes, 1};
1284  mxArray* boundaryList = mxCreateNumericArray(2, dims, mxINT32_CLASS, mxREAL);
1285  int* dest = (int*) mxGetData(boundaryList);
1286  int* destIter = dest;
1287  for(int i = 0; i < boundaryFlags.size(); i++)
1288  {
1289  if(boundaryFlags[i])
1290  {
1291  *destIter = i;
1292  destIter++;
1293  }
1294  }
1295  mxArray* constructArgs[] = {mat, boundaryList};
1296  mxArray* out[1];
1297  mexCallMATLAB(1, out, 2, constructArgs, "constructGraph");
1298  return out[0];
1299 }
1300 
1301 #ifdef HAVE_MUELU_INTREPID2
1302 template<>
1303 mxArray* saveDataToMatlab(RCP<FieldContainer_ordinal>& data)
1304 {
1305  int rank = data->rank();
1306  // NOTE: Only supports rank 2 arrays
1307  if(rank!=2)
1308  throw std::runtime_error("Error: Only rank two FieldContainers are supported.");
1309 
1310  int nr = data->dimension(0);
1311  int nc = data->dimension(1);
1312 
1313  mwSize dims[]={(mwSize)nr,(mwSize)nc};
1314  mxArray* mxa = mxCreateNumericArray(2,dims, mxINT32_CLASS, mxREAL);
1315  int *array = (int*) mxGetData(mxa);
1316 
1317  for(int col = 0; col < nc; col++)
1318  {
1319  for(int row = 0; row < nr; row++)
1320  {
1321  array[col * nr + row] = (*data)(row,col);
1322  }
1323  }
1324  return mxa;
1325 }
1326 #endif
1327 
1328 
1329 template<typename T>
1331 {
1332  data = loadDataFromMatlab<T>(mxa);
1333 }
1334 
1335 template<typename T>
1337 {
1338  return saveDataToMatlab<T>(data);
1339 }
1340 
1341 template<typename T>
1342 MuemexData<T>::MuemexData(T& dataToCopy, MuemexType dataType) : MuemexArg(dataType)
1343 {
1344  data = dataToCopy;
1345 }
1346 
1347 template<typename T>
1348 MuemexData<T>::MuemexData(T& dataToCopy) : MuemexData(dataToCopy, getMuemexType(dataToCopy)) {}
1349 
1350 template<typename T>
1352 {
1353  return data;
1354 }
1355 
1356 template<typename T>
1357 void MuemexData<T>::setData(T& newData)
1358 {
1359  this->data = newData;
1360 }
1361 
1362 /* ***************************** */
1363 /* More Template Functions */
1364 /* ***************************** */
1365 
1366 template<typename T>
1367 void addLevelVariable(const T& data, std::string& name, Level& lvl, const Factory * fact)
1368 {
1369  lvl.AddKeepFlag(name, fact, MueLu::UserData);
1370  lvl.Set<T>(name, data, fact);
1371 }
1372 
1373 template<typename T>
1374 const T& getLevelVariable(std::string& name, Level& lvl)
1375 {
1376  try
1377  {
1378  return lvl.Get<T>(name);
1379  }
1380  catch(std::exception& e)
1381  {
1382  throw std::runtime_error("Requested custom variable " + name + " is not in the level.");
1383  }
1384 }
1385 
1386 //Functions used to put data through matlab factories - first arg is "this" pointer of matlab factory
1387 template<typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, typename Node>
1388 std::vector<Teuchos::RCP<MuemexArg>> processNeeds(const Factory* factory, std::string& needsParam, Level& lvl)
1389 {
1390  using namespace std;
1391  using namespace Teuchos;
1392  typedef RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>> Matrix_t;
1393  typedef RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> MultiVector_t;
1394  typedef RCP<Aggregates<LocalOrdinal, GlobalOrdinal, Node>> Aggregates_t;
1395  typedef RCP<AmalgamationInfo<LocalOrdinal, GlobalOrdinal, Node>> AmalgamationInfo_t;
1396  typedef RCP<MGraph> Graph_t;
1397  vector<string> needsList = tokenizeList(needsParam);
1398  vector<RCP<MuemexArg>> args;
1399  for(size_t i = 0; i < needsList.size(); i++)
1400  {
1401  if(needsList[i] == "A" || needsList[i] == "P" || needsList[i] == "R" || needsList[i]=="Ptent")
1402  {
1403  Matrix_t mydata = lvl.Get<Matrix_t>(needsList[i], factory->GetFactory(needsList[i]).get());
1404  args.push_back(rcp(new MuemexData<Matrix_t>(mydata)));
1405  }
1406  else if(needsList[i] == "Nullspace" || needsList[i] == "Coordinates")
1407  {
1408  MultiVector_t mydata = lvl.Get<MultiVector_t>(needsList[i], factory->GetFactory(needsList[i]).get());
1409  args.push_back(rcp(new MuemexData<MultiVector_t>(mydata)));
1410  }
1411  else if(needsList[i] == "Aggregates")
1412  {
1413  Aggregates_t mydata = lvl.Get<Aggregates_t>(needsList[i], factory->GetFactory(needsList[i]).get());
1414  args.push_back(rcp(new MuemexData<Aggregates_t>(mydata)));
1415  }
1416  else if(needsList[i] == "UnAmalgamationInfo")
1417  {
1418  AmalgamationInfo_t mydata = lvl.Get<AmalgamationInfo_t>(needsList[i], factory->GetFactory(needsList[i]).get());
1419  args.push_back(rcp(new MuemexData<AmalgamationInfo_t>(mydata)));
1420  }
1421  else if(needsList[i] == "Level")
1422  {
1423  int levelNum = lvl.GetLevelID();
1424  args.push_back(rcp(new MuemexData<int>(levelNum)));
1425  }
1426  else if(needsList[i] == "Graph")
1427  {
1428  Graph_t mydata = lvl.Get<Graph_t>(needsList[i], factory->GetFactory(needsList[i]).get());
1429  args.push_back(rcp(new MuemexData<Graph_t>(mydata)));
1430  }
1431  else
1432  {
1433  vector<string> words;
1434  string badNameMsg = "Custom Muemex variables in \"Needs\" list require a type and a name, e.g. \"double myVal\". \n Leading and trailing spaces are OK. \n Don't know how to handle \"" + needsList[i] + "\".\n";
1435  //compare type without case sensitivity
1436  char* buf = (char*) malloc(needsList[i].size() + 1);
1437  strcpy(buf, needsList[i].c_str());
1438  for(char* iter = buf; *iter != ' '; iter++)
1439  {
1440  if(*iter == 0)
1441  {
1442  free(buf);
1443  throw runtime_error(badNameMsg);
1444  }
1445  *iter = (char) tolower(*iter);
1446  }
1447  const char* wordDelim = " ";
1448  char* mark = strtok(buf, wordDelim);
1449  while(mark != NULL)
1450  {
1451  string wordStr(mark);
1452  words.push_back(wordStr);
1453  mark = strtok(NULL, wordDelim);
1454  }
1455  if(words.size() != 2)
1456  {
1457  free(buf);
1458  throw runtime_error(badNameMsg);
1459  }
1460  char* typeStr = (char*) words[0].c_str();
1461  if(strstr(typeStr, "ordinalvector"))
1462  {
1463  typedef RCP<Xpetra::Vector<mm_LocalOrd, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> LOVector_t;
1464  LOVector_t mydata = getLevelVariable<LOVector_t>(needsList[i], lvl);
1465  args.push_back(rcp(new MuemexData<LOVector_t>(mydata)));
1466  }
1467  else if(strstr(typeStr, "map"))
1468  {
1469  typedef RCP<Xpetra::Map<mm_LocalOrd, mm_GlobalOrd, mm_node_t>> Map_t;
1470  Map_t mydata = getLevelVariable<Map_t>(needsList[i], lvl);
1471  args.push_back(rcp(new MuemexData<Map_t>(mydata)));
1472  }
1473  else if(strstr(typeStr, "scalar"))
1474  {
1475  Scalar mydata = getLevelVariable<Scalar>(needsList[i], lvl);
1476  args.push_back(rcp(new MuemexData<Scalar>(mydata)));
1477  }
1478  else if(strstr(typeStr, "double"))
1479  {
1480  double mydata = getLevelVariable<double>(needsList[i], lvl);
1481  args.push_back(rcp(new MuemexData<double>(mydata)));
1482  }
1483  else if(strstr(typeStr, "complex"))
1484  {
1485  complex_t mydata = getLevelVariable<complex_t>(needsList[i], lvl);
1486  args.push_back(rcp(new MuemexData<complex_t>(mydata)));
1487  }
1488  else if(strstr(typeStr, "matrix"))
1489  {
1490  Matrix_t mydata = getLevelVariable<Matrix_t>(needsList[i], lvl);
1491  args.push_back(rcp(new MuemexData<Matrix_t>(mydata)));
1492  }
1493  else if(strstr(typeStr, "multivector"))
1494  {
1495  MultiVector_t mydata = getLevelVariable<MultiVector_t>(needsList[i], lvl);
1496  args.push_back(rcp(new MuemexData<MultiVector_t>(mydata)));
1497  }
1498  else if(strstr(typeStr, "int"))
1499  {
1500  int mydata = getLevelVariable<int>(needsList[i], lvl);
1501  args.push_back(rcp(new MuemexData<int>(mydata)));
1502  }
1503  else if(strstr(typeStr, "string"))
1504  {
1505  string mydata = getLevelVariable<string>(needsList[i], lvl);
1506  args.push_back(rcp(new MuemexData<string>(mydata)));
1507  }
1508  else
1509  {
1510  free(buf);
1511  throw std::runtime_error(words[0] + " is not a known variable type.");
1512  }
1513  free(buf);
1514  }
1515  }
1516  return args;
1517 }
1518 
1519 template<typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, typename Node>
1520 void processProvides(std::vector<Teuchos::RCP<MuemexArg>>& mexOutput, const Factory* factory, std::string& providesParam, Level& lvl)
1521 {
1522  using namespace std;
1523  using namespace Teuchos;
1524  typedef RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>> Matrix_t;
1525  typedef RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> MultiVector_t;
1526  typedef RCP<Aggregates<LocalOrdinal, GlobalOrdinal, Node>> Aggregates_t;
1527  typedef RCP<AmalgamationInfo<LocalOrdinal, GlobalOrdinal, Node>> AmalgamationInfo_t;
1528  typedef RCP<MGraph> Graph_t;
1529  vector<string> provides = tokenizeList(providesParam);
1530  for(size_t i = 0; i < size_t(provides.size()); i++)
1531  {
1532  if(provides[i] == "A" || provides[i] == "P" || provides[i] == "R" || provides[i]=="Ptent")
1533  {
1534  RCP<MuemexData<Matrix_t>> mydata = Teuchos::rcp_static_cast<MuemexData<Matrix_t>>(mexOutput[i]);
1535  lvl.Set(provides[i], mydata->getData(), factory);
1536  }
1537  else if(provides[i] == "Nullspace" || provides[i] == "Coordinates")
1538  {
1539  RCP<MuemexData<MultiVector_t>> mydata = Teuchos::rcp_static_cast<MuemexData<MultiVector_t>>(mexOutput[i]);
1540  lvl.Set(provides[i], mydata->getData(), factory);
1541  }
1542  else if(provides[i] == "Aggregates")
1543  {
1544  RCP<MuemexData<Aggregates_t>> mydata = Teuchos::rcp_static_cast<MuemexData<Aggregates_t>>(mexOutput[i]);
1545  lvl.Set(provides[i], mydata->getData(), factory);
1546  }
1547  else if(provides[i] == "UnAmalgamationInfo")
1548  {
1549  RCP<MuemexData<AmalgamationInfo_t>> mydata = Teuchos::rcp_static_cast<MuemexData<AmalgamationInfo_t>>(mexOutput[i]);
1550  lvl.Set(provides[i], mydata->getData(), factory);
1551  }
1552  else if(provides[i] == "Graph")
1553  {
1554  RCP<MuemexData<Graph_t>> mydata = Teuchos::rcp_static_cast<MuemexData<Graph_t>>(mexOutput[i]);
1555  lvl.Set(provides[i], mydata->getData(), factory);
1556  }
1557  else
1558  {
1559  vector<string> words;
1560  string badNameMsg = "Custom Muemex variables in \"Provides\" list require a type and a name, e.g. \"double myVal\". \n Leading and trailing spaces are OK. \n Don't know how to handle \"" + provides[i] + "\".\n";
1561  //compare type without case sensitivity
1562  char* buf = (char*) malloc(provides[i].size() + 1);
1563  strcpy(buf, provides[i].c_str());
1564  for(char* iter = buf; *iter != ' '; iter++)
1565  {
1566  if(*iter == 0)
1567  {
1568  free(buf);
1569  throw runtime_error(badNameMsg);
1570  }
1571  *iter = (char) tolower(*iter);
1572  }
1573  const char* wordDelim = " ";
1574  char* mark = strtok(buf, wordDelim);
1575  while(mark != NULL)
1576  {
1577  string wordStr(mark);
1578  words.push_back(wordStr);
1579  mark = strtok(NULL, wordDelim);
1580  }
1581  if(words.size() != 2)
1582  {
1583  free(buf);
1584  throw runtime_error(badNameMsg);
1585  }
1586  const char* typeStr = words[0].c_str();
1587  if(strstr(typeStr, "ordinalvector"))
1588  {
1589  typedef RCP<Xpetra::Vector<mm_LocalOrd, mm_LocalOrd, mm_GlobalOrd, mm_node_t>> LOVector_t;
1590  RCP<MuemexData<LOVector_t>> mydata = Teuchos::rcp_static_cast<MuemexData<LOVector_t>>(mexOutput[i]);
1591  addLevelVariable<LOVector_t>(mydata->getData(), words[1], lvl, factory);
1592  }
1593  else if(strstr(typeStr, "map"))
1594  {
1595  typedef RCP<Xpetra::Map<mm_LocalOrd, mm_GlobalOrd, mm_node_t>> Map_t;
1596  RCP<MuemexData<Map_t>> mydata = Teuchos::rcp_static_cast<MuemexData<Map_t>>(mexOutput[i]);
1597  addLevelVariable<Map_t>(mydata->getData(), words[1], lvl, factory);
1598  }
1599  else if(strstr(typeStr, "scalar"))
1600  {
1601  RCP<MuemexData<Scalar>> mydata = Teuchos::rcp_static_cast<MuemexData<Scalar>>(mexOutput[i]);
1602  addLevelVariable<Scalar>(mydata->getData(), words[1], lvl, factory);
1603  }
1604  else if(strstr(typeStr, "double"))
1605  {
1606  RCP<MuemexData<double>> mydata = Teuchos::rcp_static_cast<MuemexData<double>>(mexOutput[i]);
1607  addLevelVariable<double>(mydata->getData(), words[1], lvl, factory);
1608  }
1609  else if(strstr(typeStr, "complex"))
1610  {
1611  RCP<MuemexData<complex_t>> mydata = Teuchos::rcp_static_cast<MuemexData<complex_t>>(mexOutput[i]);
1612  addLevelVariable<complex_t>(mydata->getData(), words[1], lvl, factory);
1613  }
1614  else if(strstr(typeStr, "matrix"))
1615  {
1616  RCP<MuemexData<Matrix_t>> mydata = Teuchos::rcp_static_cast<MuemexData<Matrix_t>>(mexOutput[i]);
1617  addLevelVariable<Matrix_t>(mydata->getData(), words[1], lvl, factory);
1618  }
1619  else if(strstr(typeStr, "multivector"))
1620  {
1621  RCP<MuemexData<MultiVector_t>> mydata = Teuchos::rcp_static_cast<MuemexData<MultiVector_t>>(mexOutput[i]);
1622  addLevelVariable<MultiVector_t>(mydata->getData(), words[1], lvl, factory);
1623  }
1624  else if(strstr(typeStr, "int"))
1625  {
1626  RCP<MuemexData<int>> mydata = Teuchos::rcp_static_cast<MuemexData<int>>(mexOutput[i]);
1627  addLevelVariable<int>(mydata->getData(), words[1], lvl, factory);
1628  }
1629  else if(strstr(typeStr, "bool"))
1630  {
1631  RCP<MuemexData<bool> > mydata = Teuchos::rcp_static_cast<MuemexData<bool> >(mexOutput[i]);
1632  addLevelVariable<bool>(mydata->getData(), words[1], lvl, factory);
1633  }
1634  else if(strstr(typeStr, "string"))
1635  {
1636  RCP<MuemexData<string>> mydata = Teuchos::rcp_static_cast<MuemexData<string>>(mexOutput[i]);
1637  addLevelVariable<string>(mydata->getData(), words[1], lvl, factory);
1638  }
1639  else
1640  {
1641  free(buf);
1642  throw std::runtime_error(words[0] + " is not a known variable type.");
1643  }
1644  free(buf);
1645  }
1646  }
1647 }
1648 
1649 // Throwable Stubs for long long
1650 
1651 template<>
1652 std::vector<Teuchos::RCP<MuemexArg>> processNeeds<double,mm_LocalOrd,long long,mm_node_t>(const Factory* factory, std::string& needsParam, Level& lvl) {
1653  throw std::runtime_error("Muemex does not support long long for global indices");
1654 }
1655 
1656 template<>
1657 std::vector<Teuchos::RCP<MuemexArg>> processNeeds<complex_t,mm_LocalOrd,long long,mm_node_t>(const Factory* factory, std::string& needsParam, Level& lvl) {
1658  throw std::runtime_error("Muemex does not support long long for global indices");
1659 }
1660 
1661 template<>
1662 void processProvides<double,mm_LocalOrd,long long,mm_node_t>(std::vector<Teuchos::RCP<MuemexArg>>& mexOutput, const Factory* factory, std::string& providesParam, Level& lvl) {
1663  throw std::runtime_error("Muemex does not support long long for global indices");
1664 }
1665 
1666 template<>
1667 void processProvides<complex_t,mm_LocalOrd,long long,mm_node_t>(std::vector<Teuchos::RCP<MuemexArg>>& mexOutput, const Factory* factory, std::string& providesParam, Level& lvl) {
1668  throw std::runtime_error("Muemex does not support long long for global indices");
1669 }
1670 
1671 
1672 }// end namespace
1673 #endif //HAVE_MUELU_MATLAB error handler
1674 #endif //MUELU_MATLABUTILS_DEF_HPP guard
std::vector< Teuchos::RCP< MuemexArg > > processNeeds< double, mm_LocalOrd, long long, mm_node_t >(const Factory *factory, std::string &needsParam, Level &lvl)
std::vector< std::string > tokenizeList(const std::string &params)
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access). Usage: Level->Get< RCP<Matrix> >("A", factory) if factory == NULL => use default factory.
mxArray * createMatlabSparse< complex_t >(int numRows, int numCols, int nnz)
bool rewrap_ints
mxArray * saveDataToMatlab(RCP< MGraph > &data)
MuemexType getMuemexType< string >()
MueLu representation of a compressed row storage graph.
void processProvides< complex_t, mm_LocalOrd, long long, mm_node_t >(std::vector< Teuchos::RCP< MuemexArg >> &mexOutput, const Factory *factory, std::string &providesParam, Level &lvl)
User data are always kept. This flag is set automatically when Level::Set("data", data) is used...
std::string tolower(const std::string &str)
Namespace for MueLu classes and methods.
void fillMatlabArray< double >(double *array, const mxArray *mxa, int n)
template string loadDataFromMatlab< string >(const mxArray *mxa)
MuemexType getMuemexType(const T &data)
std::vector< Teuchos::RCP< MuemexArg > > processNeeds(const Factory *factory, std::string &needsParam, Level &lvl)
void addLevelVariable(const T &data, std::string &name, Level &lvl, const FactoryBase *fact=NoFactory::get())
int GetLevelID() const
Return level number.
Definition: MueLu_Level.cpp:76
void fillMatlabArray< complex_t >(complex_t *array, const mxArray *mxa, int n)
void processProvides< double, mm_LocalOrd, long long, mm_node_t >(std::vector< Teuchos::RCP< MuemexArg >> &mexOutput, const Factory *factory, std::string &providesParam, Level &lvl)
mxArray * createMatlabSparse< double >(int numRows, int numCols, int nnz)
int * mwIndex_to_int(int N, mwIndex *mwi_array)
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
template complex_t loadDataFromMatlab< complex_t >(const mxArray *mxa)
template int loadDataFromMatlab< int >(const mxArray *mxa)
template bool loadDataFromMatlab< bool >(const mxArray *mxa)
const T & getLevelVariable(std::string &name, Level &lvl)
MuemexType getMuemexType< int >()
mxArray * createMatlabMultiVector< complex_t >(int numRows, int numCols)
std::vector< Teuchos::RCP< MuemexArg > > processNeeds< complex_t, mm_LocalOrd, long long, mm_node_t >(const Factory *factory, std::string &needsParam, Level &lvl)
MuemexType getMuemexType(const RCP< MGraph > &data)
void AddKeepFlag(const std::string &ename, const FactoryBase *factory=NoFactory::get(), KeepType keep=MueLu::Keep)
MuemexType getMuemexType< bool >()
void Set(const std::string &ename, const T &entry, const FactoryBase *factory=NoFactory::get())
RCP< Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > TpetraMultiVector_To_XpetraMultiVector(const Teuchos::RCP< Tpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &Vtpetra)
std::complex< double > complex_t
mxArray * createMatlabMultiVector< double >(int numRows, int numCols)
template double loadDataFromMatlab< double >(const mxArray *mxa)
MueLu::Aggregates< mm_LocalOrd, mm_GlobalOrd, mm_node_t > MAggregates
MuemexType getMuemexType< double >()
Tpetra::Map muemex_map_type
void processProvides(std::vector< Teuchos::RCP< MuemexArg >> &mexOutput, const Factory *factory, std::string &providesParam, Level &lvl)
RCP< Xpetra::Matrix< SC, LO, GO, NO > > TpetraCrs_To_XpetraMatrix(const Teuchos::RCP< Tpetra::CrsMatrix< SC, LO, GO, NO > > &Atpetra)
const RCP< const FactoryBase > GetFactory(const std::string &varName) const
Default implementation of FactoryAcceptor::GetFactory()
MuemexType getMuemexType< complex_t >()
int mwIndex