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