int main (int argc, char *argv[]) { /* Timing vars */ // double ut1,ut2,st1,st2,wt1,wt2; double wt1,wt2; /* Matrix */ int n, nnz; double fnorm; CSRMatrix matrix; /* Preconditioner */ CSRMatrix Factors; /* Files */ char *DriverConfigFileName, *SolverConfigFileName; /* Driver and solver I/O arrays and parameters */ double *evals, *evecs, *rnorms; driver_params driver; primme_params primme; primme_preset_method method; #ifdef Cplusplus /* C++ has a stricter type checking */ void (*precond_function)(void *, void *, int *, primme_params *); #else void *precond_function; #endif /* Other miscellaneous items */ int i; int ret; /* --------------------------------------------------------------------- */ /* Read matrix and driver setup */ /* --------------------------------------------------------------------- */ /* ------------------------------------------------------- */ /* Get from command line the names for the 2 config files */ /* ------------------------------------------------------- */ if (argc == 3) { DriverConfigFileName = argv[1]; SolverConfigFileName = argv[2]; } /* ----------------------------- */ /* Read in the driver parameters */ /* ----------------------------- */ if (read_driver_params(DriverConfigFileName, &driver) < 0) { fprintf(stderr, "Reading driver parameters failed\n"); return(-1); } /* ------------------------------------------ */ /* Read the matrix and store it in CSR format */ /* ------------------------------------------ */ fprintf(stderr," Matrix: %s\n",driver.matrixFileName); if (!strcmp("mtx", &driver.matrixFileName[strlen(driver.matrixFileName)-3])) { // coordinate format storing both lower and upper triangular parts ret = readfullMTX(driver.matrixFileName, &matrix.AElts, &matrix.JA, &matrix.IA, &n, &nnz); if (ret < 0) { fprintf(stderr, "ERROR: Could not read matrix file\n"); return(-1); } } else if (driver.matrixFileName[strlen(driver.matrixFileName)-1] == 'U') { // coordinate format storing only upper triangular part ret = readUpperMTX(driver.matrixFileName, &matrix.AElts, &matrix.JA, &matrix.IA, &n, &nnz); if (ret < 0) { fprintf(stderr, "ERROR: Could not read matrix file\n"); return(-1); } } else { //Harwell Boeing format NOT IMPLEMENTED //ret = readmt() ret = -1; if (ret < 0) { fprintf(stderr, "ERROR: Could not read matrix file\n"); return(-1); } } fnorm = frobeniusNorm(n, matrix.IA, matrix.AElts); /* ------------------------------------------------------------------------- */ /* Set up preconditioner if needed. We provide these sample options */ /* in driver.PrecChoice: (driver.PrecChoice is read in read_driver_params) */ /* choice = 0 no preconditioner */ /* choice = 1 K=Diag(A-shift), shift provided once by user */ /* choice = 2 K=Diag(A-shift_i), shifts provided by primme every step */ /* choice = 3 K=ILUT(A-shift) , shift provided once by user */ /* ------------------------------------------------------------------------- */ ret = create_preconditioner (matrix, &Factors, &precond_function, n, nnz, driver); if (ret < 0) { fprintf(stderr, "ERROR: Could not create requested preconditioner \n"); return(-1); } /* --------------------------------------------------------------------- */ /* Primme solver setup */ /* primme_initialize (not needed if ALL primme struct members set)*/ /* primme_set_method (bypass it to fully customize your solver) */ /* --------------------------------------------------------------------- */ /* ----------------------------- */ /* Initialize defaults in primme */ /* ----------------------------- */ primme_initialize(&primme); /* --------------------------------------- */ /* Read in the primme configuration file */ /* --------------------------------------- */ primme.n = n; primme.aNorm = fnorm; /* ||A||_frobenius. A configFile entry overwrites it */ if (read_solver_params(SolverConfigFileName, driver.outputFileName, &primme, &method) < 0) { fprintf(stderr, "Reading solver parameters failed\n"); return(-1); } /* --------------------------------------- */ /* Pick one of the default methods(if set) */ /* --------------------------------------- */ if (primme_set_method(method, &primme) < 0 ) { fprintf(primme.outputFile, "No preset method. Using custom settings\n"); } /* --------------------------------------- */ /* Optional: report memory requirements */ /* --------------------------------------- */ ret = dprimme(NULL,NULL,NULL,&primme); fprintf(primme.outputFile,"PRIMME will allocate the following memory:\n"); fprintf(primme.outputFile,"real workspace, %ld bytes\n",primme.realWorkSize); fprintf(primme.outputFile,"int workspace, %d bytes\n",primme.intWorkSize); /* --------------------------------------- */ /* Set up matrix vector and preconditioner */ /* --------------------------------------- */ primme.matrixMatvec = MatrixMatvec; primme.applyPreconditioner = precond_function; /* --------------------------------------- */ /* Optional: provide matrix/preconditioner */ /* --------------------------------------- */ primme.matrix = &matrix; primme.preconditioner = &Factors; /* --------------------------------------- */ /* Display given parameter configuration */ /* Place this after the dprimme() to see */ /* any changes dprimme() made to primme */ /* --------------------------------------- */ fprintf(primme.outputFile," Matrix: %s\n",driver.matrixFileName); primme_display_params(primme); /* --------------------------------------------------------------------- */ /* Run the dprimme solver */ /* --------------------------------------------------------------------- */ /* Allocate space for converged Ritz values and residual norms */ evals = (double *)primme_calloc(primme.numEvals, sizeof(double), "evals"); evecs = (double *)primme_calloc(primme.n* (primme.numEvals+primme.maxBlockSize), sizeof(double), "evecs"); rnorms = (double *)primme_calloc(primme.numEvals, sizeof(double), "rnorms"); /* ------------------------ */ /* Initial guess (optional) */ /* ------------------------ */ for (i=0;i<primme.n;i++) evecs[i]=1/sqrt(primme.n); /* ------------- */ /* Call primme */ /* ------------- */ wt1 = primme_wTimer2(1); // primme_get_time(&ut1,&st1); ret = dprimme(evals, evecs, rnorms, &primme); wt2 = primme_wTimer2(0); // primme_get_time(&ut2,&st2); /* --------------------------------------------------------------------- */ /* Reporting */ /* --------------------------------------------------------------------- */ primme_PrintStackTrace(primme); fprintf(primme.outputFile, "Wallclock Runtime : %-f\n", wt2-wt1); // fprintf(primme.outputFile, "User Time : %f seconds\n", ut2-ut1); // fprintf(primme.outputFile, "Syst Time : %f seconds\n", st2-st1); if (primme.procID == 0) { for (i=0; i < primme.numEvals; i++) { fprintf(primme.outputFile, "Eval[%d]: %-22.15E rnorm: %-22.15E\n", i+1, evals[i], rnorms[i]); } fprintf(primme.outputFile, " %d eigenpairs converged\n", primme.initSize); fprintf(primme.outputFile, "Tolerance : %-22.15E\n", primme.aNorm*primme.eps); fprintf(primme.outputFile, "Iterations: %-d\n", primme.stats.numOuterIterations); fprintf(primme.outputFile, "Restarts : %-d\n", primme.stats.numRestarts); fprintf(primme.outputFile, "Matvecs : %-d\n", primme.stats.numMatvecs); fprintf(primme.outputFile, "Preconds : %-d\n", primme.stats.numPreconds); fprintf(primme.outputFile, "\n\n#,%d,%.1f\n\n", primme.stats.numMatvecs, wt2-wt1); switch (primme.dynamicMethodSwitch) { case -1: fprintf(primme.outputFile, "Recommended method for next run: DEFAULT_MIN_MATVECS\n"); break; case -2: fprintf(primme.outputFile, "Recommended method for next run: DEFAULT_MIN_TIME\n"); break; case -3: fprintf(primme.outputFile, "Recommended method for next run: DYNAMIC (close call)\n"); break; } } if (ret != 0) { fprintf(primme.outputFile, "Error: dprimme returned with nonzero exit status\n"); return -1; } fclose(primme.outputFile); primme_Free(&primme); return(0); }
int main (int argc, char *argv[]) { /* Timing vars */ double ut1,ut2,st1,st2,wt1,wt2; /* Matrix */ int n, nLocal, nnz; double fnorm; CSRMatrix matrix; // The matrix in simple SPARSKIT CSR format Matrix *Par_matrix; // Pointer to the matrix in Parasails CSR format /* Permutation/partitioning stuff */ int *mask, *map; int *fg2or, *or2fg; /* Preconditioner */ ParaSails *Par_Factors; // Pointer to the matrix in Parasails CSR format /* Files */ char *DriverConfigFileName, *SolverConfigFileName; char partFileName[512]; FILE *partFile; /* Driver and solver I/O arrays and parameters */ double *evals, *evecs, *rnorms; driver_params driver; primme_params primme; primme_preset_method method; #ifdef Cplusplus /* C++ has a stricter type checking */ void (*precond_function)(void *, void *, int *, primme_params *); #else void *precond_function; #endif /* Other miscellaneous items */ int i,j; int ret, modulo; int rangeStart; int rangeEnd; int numProcs, procID; MPI_Comm comm; /* --------------------------------------------------------------------- */ /* MPI INITIALIZATION */ /* --------------------------------------------------------------------- */ MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &numProcs); MPI_Comm_rank(MPI_COMM_WORLD, &procID); comm = MPI_COMM_WORLD; /* --------------------------------------------------------------------- */ /* Read matrix and driver setup */ /* --------------------------------------------------------------------- */ /* ------------------------------------------------------- */ /* Get from command line the names for the 2 config files */ /* ------------------------------------------------------- */ if (argc == 3) { DriverConfigFileName = argv[1]; SolverConfigFileName = argv[2]; } else { MPI_Finalize(); return(-1); } /* ----------------------------- */ /* Read in the driver parameters */ /* ----------------------------- */ if (read_driver_params(DriverConfigFileName, &driver) < 0) { fprintf(stderr, "Reading driver parameters failed\n"); fflush(stderr); MPI_Finalize(); return(-1); } /* ------------------------------------------ */ /* Read the matrix and store it in CSR format */ /* ------------------------------------------ */ if (procID == 0) { fprintf(stdout," Matrix: %s\n",driver.matrixFileName); fflush(stdout); if (!strcmp("mtx", &driver.matrixFileName[strlen(driver.matrixFileName)-3])) { // coordinate format storing both lower and upper triangular parts ret = readfullMTX(driver.matrixFileName, &matrix.AElts, &matrix.JA, &matrix.IA, &n, &nnz); if (ret < 0) { fprintf(stderr, "ERROR: Could not read matrix file\n"); MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE); return(-1); } } else if (driver.matrixFileName[strlen(driver.matrixFileName)-1] == 'U') { // coordinate format storing only upper triangular part ret = readUpperMTX(driver.matrixFileName, &matrix.AElts, &matrix.JA, &matrix.IA, &n, &nnz); if (ret < 0) { fprintf(stderr, "ERROR: Could not read matrix file\n"); MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE); return(-1); } } else { //Harwell Boeing format NOT IMPLEMENTED //ret = readmt() ret = -1; if (ret < 0) { fprintf(stderr, "ERROR: Could not read matrix file\n"); MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE); return(-1); } } } // if procID == 0 /* ----------------------------------------------------------- */ // Allocate space on other processors and broadcast the matrix /* ----------------------------------------------------------- */ MPI_Bcast(&nnz, 1, MPI_INT, 0, MPI_COMM_WORLD); MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); if (procID != 0) { matrix.AElts = (double *)primme_calloc(nnz, sizeof(double), "A"); matrix.JA = (int *)primme_calloc(nnz, sizeof(int), "JA"); matrix.IA = (int *)primme_calloc(n+1, sizeof(int), "IA"); } else { // Proc 0 converts CSR to C indexing for (i=0; i < n+1; i++) { matrix.IA[i]--; } for (i=0; i < nnz; i++) { matrix.JA[i]--; } } MPI_Bcast(matrix.AElts, nnz, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(matrix.IA, n+1, MPI_INT, 0, MPI_COMM_WORLD); MPI_Bcast(matrix.JA, nnz, MPI_INT, 0, MPI_COMM_WORLD); fnorm = frobeniusNorm(n, matrix.IA, matrix.AElts); /* ---------------------------------------------------------------------- */ /* Partitioning of the matrix among the processors */ /* ---------------------------------------------------------------------- */ mask = (int *)primme_calloc(n, sizeof(int), "mask"); map = (int *)primme_calloc(numProcs+1, sizeof(int), "map"); fg2or = (int *)primme_calloc(n, sizeof(int), "fg2or"); or2fg = (int *)primme_calloc(n, sizeof(int), "or2fg"); // /* * * * * * * * * * * * * * * * * * // * Read the partition from a file // * * * * * * * * * * * * * * * * * */ // sprintf(partFileName, "%s/%s", driver.partDir, driver.partId); // partFile = fopen(partFileName, "r"); // // if (partFile == 0) { // fprintf(stderr, "ERROR: Could not open '%s'\n", partFileName); // MPI_Finalize(); // return(-1); // } // // for (i = 0; i < n; i++) { // fscanf(partFile, "%d", &mask[i]); // } // // fclose(partFile); /* * * * * * * * * * * * * * * * * * * * * * * */ /* Simplistic assignment of processors to rows */ /* * * * * * * * * * * * * * * * * * * * * * * */ nLocal = n / numProcs; modulo = n % numProcs; rangeStart = 0; for (i=0; i<numProcs; i++) { rangeEnd = rangeStart + nLocal; if (i < modulo) rangeEnd = rangeEnd + 1; for (j = rangeStart; j< rangeEnd; j++) mask[j] = i; rangeStart = rangeEnd; } /* * * * * * * * * * * * * * * * * * * * * * * */ generatePermutations(n, numProcs, mask, or2fg, fg2or, map); rangeStart = map[procID]; rangeEnd = map[procID+1]-1; nLocal = rangeEnd - rangeStart+1; Par_matrix = csrToParaSails(procID, map, fg2or, or2fg, matrix.IA, matrix.JA, matrix.AElts, comm); /* ------------------------------------------------------------------------- */ /* Set up preconditioner if needed. For parallel programs the only choice */ /* in driver.PrecChoice: (driver.PrecChoice is read in read_driver_params) */ /* choice = 4 Parallel ParaSails preconditioners */ /* with parameters (level, threshold, filter, isymm) */ /* as read in read_driver_params(). */ /* ------------------------------------------------------------------------- */ if (driver.PrecChoice == 4) { Par_Factors = generate_precond(&matrix, driver.shift, n, procID, map, fg2or, or2fg, rangeStart, rangeEnd, driver.isymm, driver.level, driver.threshold, driver.filter, comm); precond_function = par_ApplyParasailsPrec; } else { Par_Factors = NULL; precond_function = NULL; // Free A as it is not further needed free(matrix.AElts); free(matrix.IA); free(matrix.JA); } free(mask); free(map); free(fg2or); free(or2fg); /* --------------------------------------------------------------------- */ /* Primme solver setup */ /* primme_initialize (not needed if ALL primme struct members set)*/ /* primme_set_method (bypass it to fully customize your solver) */ /* --------------------------------------------------------------------- */ /* ----------------------------- */ /* Initialize defaults in primme */ /* ----------------------------- */ primme_initialize(&primme); /* --------------------------------------- */ /* Read in the primme configuration file */ /* --------------------------------------- */ primme.n = n; primme.aNorm = fnorm; /* ||A||_frobenius. A configFile entry overwrites it */ if (procID == 0) { if (read_solver_params(SolverConfigFileName, driver.outputFileName, &primme, &method) < 0) { fprintf(stderr, "Reading solver parameters failed\n"); MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE); return(-1); } } /* ------------------------------------------------- */ // Send read common primme members to all processors // Setup the primme members local to this processor /* ------------------------------------------------- */ broadCast(&primme, &method, comm); primme.procID = procID; primme.numProcs = numProcs; primme.nLocal = nLocal; primme.commInfo = &comm; primme.globalSumDouble = par_GlobalSumDouble; /* --------------------------------------- */ /* Pick one of the default methods(if set) */ /* --------------------------------------- */ if (primme_set_method(method, &primme) < 0 ) { fprintf(primme.outputFile, "No preset method. Using custom settings\n"); } /* --------------------------------------- */ /* Optional: report memory requirements */ /* --------------------------------------- */ ret = dprimme(NULL,NULL,NULL,&primme); fprintf(primme.outputFile,"PRIMME will allocate the following memory:\n"); fprintf(primme.outputFile," processor %d, real workspace, %ld bytes\n", procID, primme.realWorkSize); fprintf(primme.outputFile," processor %d, int workspace, %d bytes\n", procID, primme.intWorkSize); /* --------------------------------------- */ /* Set up matrix vector and preconditioner */ /* --------------------------------------- */ primme.matrixMatvec = par_MatrixMatvec; primme.applyPreconditioner = precond_function; /* --------------------------------------- */ /* Optional: provide matrix/preconditioner */ /* --------------------------------------- */ primme.matrix = Par_matrix; primme.preconditioner = Par_Factors; /* --------------------------------------- */ /* Display given parameter configuration */ /* Place this after the dprimme() to see */ /* any changes dprimme() made to primme */ /* --------------------------------------- */ if (procID >= 0) { fprintf(primme.outputFile," Matrix: %s\n",driver.matrixFileName); primme_display_params(primme); } /* --------------------------------------------------------------------- */ /* Run the dprimme solver */ /* --------------------------------------------------------------------- */ /* Allocate space for converged Ritz values and residual norms */ evals = (double *)primme_calloc(primme.numEvals, sizeof(double), "evals"); evecs = (double *)primme_calloc(primme.nLocal* (primme.numEvals+primme.maxBlockSize), sizeof(double), "evecs"); rnorms = (double *)primme_calloc(primme.numEvals, sizeof(double), "rnorms"); /* ------------------------ */ /* Initial guess (optional) */ /* ------------------------ */ for (i=0;i<primme.nLocal;i++) evecs[i]=1/sqrt(primme.n); /* ------------- */ /* Call primme */ /* ------------- */ wt1 = primme_get_wtime(); primme_get_time(&ut1,&st1); ret = dprimme(evals, evecs, rnorms, &primme); wt2 = primme_get_wtime(); primme_get_time(&ut2,&st2); /* --------------------------------------------------------------------- */ /* Reporting */ /* --------------------------------------------------------------------- */ if (procID == 0) { primme_PrintStackTrace(primme); } fprintf(primme.outputFile, "Wallclock Runtime : %-f\n", wt2-wt1); fprintf(primme.outputFile, "User Time : %f seconds\n", ut2-ut1); fprintf(primme.outputFile, "Syst Time : %f seconds\n", st2-st1); if (primme.procID == 0) { for (i=0; i < primme.numEvals; i++) { fprintf(primme.outputFile, "Eval[%d]: %-22.15E rnorm: %-22.15E\n", i+1, evals[i], rnorms[i]); } fprintf(primme.outputFile, " %d eigenpairs converged\n", primme.initSize); fprintf(primme.outputFile, "Tolerance : %-22.15E\n", primme.aNorm*primme.eps); fprintf(primme.outputFile, "Iterations: %-d\n", primme.stats.numOuterIterations); fprintf(primme.outputFile, "Restarts : %-d\n", primme.stats.numRestarts); fprintf(primme.outputFile, "Matvecs : %-d\n", primme.stats.numMatvecs); fprintf(primme.outputFile, "Preconds : %-d\n", primme.stats.numPreconds); fprintf(primme.outputFile, "\n\n#,%d,%.1f\n\n", primme.stats.numMatvecs, wt2-wt1); switch (primme.dynamicMethodSwitch) { case -1: fprintf(primme.outputFile, "Recommended method for next run: DEFAULT_MIN_MATVECS\n"); break; case -2: fprintf(primme.outputFile, "Recommended method for next run: DEFAULT_MIN_TIME\n"); break; case -3: fprintf(primme.outputFile, "Recommended method for next run: DYNAMIC (close call)\n"); break; } } if (ret != 0 && procID == 0) { fprintf(primme.outputFile, "Error: dprimme returned with nonzero exit status: %d \n",ret); return -1; } fflush(primme.outputFile); fclose(primme.outputFile); primme_Free(&primme); fflush(stdout); fflush(stderr); MPI_Barrier(comm); MPI_Finalize(); return(0); }