xref: /petsc/src/mat/tests/ex231.cxx (revision ccb4e88a40f0b86eaeca07ff64c64e4de2fae686)
1 static char help[] = "A test for MatAssembly that heavily relies on PetscSortIntWithArrayPair\n";
2 
3 /*
4    The characteristic of the array (about 4M in length) to sort in this test is that it has
5    many duplicated values that already clustered together (around 95 duplicates per unique integer).
6 
7    It was gotten from a petsc performance bug report from the Moose project. One can use
8    it for future performance study.
9 
10    Contributed-by: Fande Kong <fdkong.jd@gmail.com>, John Peterson <jwpeterson@gmail.com>
11  */
12 
13 // PETSc includes
14 #include <petscmat.h>
15 
16 // C++ includes
17 #include <iostream>
18 #include <fstream>
19 #include <sstream>
20 #include <algorithm>
21 #include <vector>
22 #include <string>
23 #include <set>
24 
25 int main (int argc, char** argv)
26 {
27   PetscErrorCode ierr;
28   PetscMPIInt    size, rank;
29   char           file[2][PETSC_MAX_PATH_LEN];
30   PetscBool      flg;
31   const unsigned int n_dofs = 26559;
32   unsigned int   first_local_index;
33   unsigned int   last_local_index;
34 
35   ierr = PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr;
36   ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRMPI(ierr);
37   ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRMPI(ierr);
38   if (size > 2) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"This example is for <=2 procs");
39 
40   ierr = PetscOptionsGetString(NULL,NULL,"-f0",file[0],sizeof(file[0]),&flg);CHKERRQ(ierr);
41   if (!flg) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_USER,"Must indicate dof indices file for rank 0 with -f0 option");
42   if (size == 2) {
43     ierr = PetscOptionsGetString(NULL,NULL,"-f1",file[1],sizeof(file[1]),&flg);CHKERRQ(ierr);
44     if (!flg) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_USER,"Must indicate dof indices file for rank 1 with -f1 option");
45   }
46 
47   if (size == 1) {
48     first_local_index = 0;
49     last_local_index  = 26559;
50   } else {
51     if (rank == 0) {
52       first_local_index = 0;
53       last_local_index  = 13911;
54     } else {
55       first_local_index = 13911;
56       last_local_index  = 26559;
57     }
58   }
59 
60   // Read element dof indices from files
61   std::vector<std::vector<std::vector<PetscInt> > > elem_dof_indices(size);
62   for (PetscInt proc_id = 0; proc_id < size; ++proc_id) {
63     std::string line;
64     std::ifstream dof_file(file[proc_id]);
65     if (dof_file.good()) {
66       while (std::getline (dof_file,line)) {
67         std::vector<PetscInt> dof_indices;
68         std::stringstream sstream(line);
69         std::string token;
70         while (std::getline(sstream, token, ' ')) {dof_indices.push_back(std::atoi(token.c_str()));}
71         elem_dof_indices[proc_id].push_back(dof_indices);
72       }
73     } else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Could not open file %s",file[proc_id]);
74   }
75 
76   // Debugging: Verify we read in elem_dof_indices correctly
77   // for (unsigned int i=0; i<elem_dof_indices.size(); ++i)
78   //   {
79   //     for (unsigned int j=0; j<elem_dof_indices[i].size(); ++j)
80   //       {
81   //         for (unsigned int k=0; k<elem_dof_indices[i][j].size(); ++k)
82   //           std::cout << elem_dof_indices[i][j][k] << " ";
83   //         std::cout << std::endl;
84   //       }
85   //     std::cout << std::endl;
86   //   }
87 
88   // Set up the (global) sparsity pattern
89   std::vector< std::set< unsigned int > > sparsity(n_dofs);
90   for (PetscInt proc_id = 0; proc_id < size; ++proc_id)
91     for (unsigned int k = 0; k < elem_dof_indices[proc_id].size(); k++) {
92       std::vector<PetscInt>& dof_indices = elem_dof_indices[proc_id][k];
93       for (unsigned int i = 0; i < dof_indices.size(); ++i)
94         for (unsigned int j = 0; j < dof_indices.size(); ++j)
95           sparsity[dof_indices[i]].insert(dof_indices[j]);
96     }
97 
98   // Determine the local nonzeros on this processor
99   const unsigned int n_local_dofs = last_local_index - first_local_index;
100   std::vector<PetscInt> n_nz(n_local_dofs);
101   std::vector<PetscInt> n_oz(n_local_dofs);
102 
103   for (unsigned int i = 0; i < n_local_dofs; ++i) {
104     for (std::set<unsigned int>::iterator iter = sparsity[i+first_local_index].begin(); iter != sparsity[i+first_local_index].end(); iter++) {
105       unsigned int dof = *iter;
106       if ((dof >= first_local_index) && (dof < last_local_index)) n_nz[i]++;
107       else n_oz[i]++;
108     }
109   }
110 
111   // Debugging: print number of on/off diagonal nonzeros
112   // for (unsigned int i=0; i<n_nz.size(); ++i)
113   //   std::cout << n_nz[i] << " ";
114   // std::cout << std::endl;
115 
116   // for (unsigned int i=0; i<n_oz.size(); ++i)
117   //   std::cout << n_oz[i] << " ";
118   // std::cout << std::endl;
119 
120   // Compute and print max number of on- and off-diagonal nonzeros.
121   PetscInt n_nz_max = *std::max_element(n_nz.begin(), n_nz.end());
122   PetscInt n_oz_max = *std::max_element(n_oz.begin(), n_oz.end());
123 
124   ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "Max on-diagonal non-zeros: = %d\n", n_nz_max);CHKERRQ(ierr);
125   ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "Max off-diagonal non-zeros: = %d\n", n_oz_max);CHKERRQ(ierr);
126   ierr = PetscSynchronizedFlush(PETSC_COMM_WORLD,PETSC_STDOUT);CHKERRQ(ierr);
127 
128   // Initialize the matrix similar to what we do in the PetscMatrix
129   // ctor and init() routines.
130   Mat mat;
131   ierr = MatCreate(PETSC_COMM_WORLD, &mat);CHKERRQ(ierr);
132   ierr = MatSetSizes(mat, n_local_dofs, n_local_dofs, n_dofs, n_dofs);CHKERRQ(ierr);
133   ierr = MatSetBlockSize(mat, 1);CHKERRQ(ierr);
134   ierr = MatSetType(mat, MATAIJ);CHKERRQ(ierr); // Automatically chooses seqaij or mpiaij
135   ierr = MatSeqAIJSetPreallocation(mat, 0, &n_nz[0]);CHKERRQ(ierr);
136   ierr = MatMPIAIJSetPreallocation(mat, 0, &n_nz[0], 0, &n_oz[0]);CHKERRQ(ierr);
137   ierr = MatSetOption(mat, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);CHKERRQ(ierr);
138 
139   // Local "element" loop
140   for (unsigned int k = 0; k < elem_dof_indices[rank].size(); k++) {
141     std::vector<PetscInt>& dof_indices = elem_dof_indices[rank][k];
142     // DenseMatrix< Number >  zero_mat( dof_indices.size(), dof_indices.size());
143     // B.add_matrix( zero_mat, dof_indices);
144     std::vector<PetscScalar> ones(dof_indices.size() * dof_indices.size(), 1.);
145     ierr = MatSetValues(mat, dof_indices.size(), &dof_indices[0], dof_indices.size(), &dof_indices[0], &ones[0], ADD_VALUES);CHKERRQ(ierr);
146   }
147 
148   // Matrix assembly
149   ierr = MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
150   ierr = MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
151 
152   // Clean up
153   ierr = MatDestroy(&mat);CHKERRQ(ierr);
154   ierr = PetscFinalize();
155   return ierr;
156 }
157 /*TEST
158    build:
159       requires: !defined(PETSC_HAVE_SUN_CXX)
160 
161    test:
162       nsize: 2
163       args: -f0 ${DATAFILESPATH}/meshes/moose_dof_indices_np_2_proc_0.txt -f1 ${DATAFILESPATH}/meshes/moose_dof_indices_np_2_proc_1.txt
164       # Skip the test for Sun C++ compiler because of its warnings/errors in petscmat.h
165       requires: datafilespath
166 
167 TEST*/
168