FEI Version of the Day
fei_test_utils.cpp
00001 /*
00002 // @HEADER
00003 // ************************************************************************
00004 //             FEI: Finite Element Interface to Linear Solvers
00005 //                  Copyright (2005) Sandia Corporation.
00006 //
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the
00008 // U.S. Government retains certain rights in this software.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Alan Williams (william@sandia.gov) 
00038 //
00039 // ************************************************************************
00040 // @HEADER
00041 */
00042 
00043 #include <fei_sstream.hpp>
00044 #include <fei_fstream.hpp>
00045 
00046 #include <fei_test_utils.hpp>
00047 
00048 #include <snl_fei_Utils.hpp>
00049 #include <fei_VectorSpace.hpp>
00050 #include <fei_MatrixGraph.hpp>
00051 #include <fei_Matrix.hpp>
00052 
00053 #include <cmath>
00054 
00055 #undef fei_file
00056 #define fei_file "fei_test_utils.cpp"
00057 #include <fei_ErrMacros.hpp>
00058 
00059 namespace fei_test_utils {
00060 
00061 std::string construct_filename(int argc, char** argv)
00062 {
00063   std::string path(".");
00064   std::string filename;
00065   std::string result;
00066 
00067   int dashDarg = whichArg(argc, argv, "-d");
00068 
00069   int dashIarg = whichArg(argc, argv, "-i");
00070 
00071   if (dashIarg < 0) {
00072     fei::console_out() << "fei_test_utils::construct_filename: argument '-i' not found."
00073              << FEI_ENDL;
00074     return(result);
00075   }
00076 
00077   if (dashDarg > -1 && argc > dashDarg+1) {
00078     if (argv[dashDarg+1] != 0) {
00079       path = argv[dashDarg+1];
00080     }
00081   }
00082 
00083   if (argc > dashIarg+1) {
00084     if (argv[dashIarg+1] != 0) {
00085       filename = argv[dashIarg+1];
00086     }
00087   }
00088 
00089   FEI_OSTRINGSTREAM osstr;
00090   osstr << path;
00091 
00092   std::size_t string_length = path.size();
00093   if (path[string_length-1] != '/') osstr << "/";
00094   
00095   osstr << filename;
00096 
00097   return( osstr.str() );
00098 }
00099 
00100 int initialize_mpi(int argc, char** argv, int& localProc, int& numProcs)
00101 {
00102 #ifndef FEI_SER
00103   if (MPI_Init(&argc, &argv) != MPI_SUCCESS) ERReturn(-1);
00104   if (MPI_Comm_rank(MPI_COMM_WORLD, &localProc) != MPI_SUCCESS) ERReturn(-1);
00105   if (MPI_Comm_size(MPI_COMM_WORLD, &numProcs) != MPI_SUCCESS) ERReturn(-1);
00106 #else
00107   localProc = 0;
00108   numProcs = 1;
00109 #endif
00110   return(0);
00111 }
00112 
00113 bool bool_arg(const char* flag, int argc, char** argv,
00114                        bool default_result)
00115 {
00116   int arg_index = whichArg(argc, argv, flag);
00117   bool result = default_result;
00118   if (arg_index > -1) {
00119     if (argc > arg_index+1) {
00120       if (argv[arg_index+1] != 0) {
00121         std::string strarg(argv[arg_index+1]);
00122         if (strarg == "yes" || strarg == "Yes" || strarg == "YES" ||
00123             strarg == "true" || strarg == "True" || strarg == "TRUE") {
00124           result = true;
00125         }
00126 
00127         if (strarg == "no" || strarg == "No" || strarg == "NO" ||
00128             strarg == "false" || strarg == "False" || strarg == "FALSE") {
00129           result = false;
00130         }
00131       }
00132     }
00133   }
00134 
00135   return(result);
00136 }
00137 
00138 std::string get_arg_value(const char* flag, int argc, char** argv)
00139 {
00140   std::string result;
00141   int arg_index = whichArg(argc, argv, flag);
00142   if (arg_index > -1) {
00143     if (argc > arg_index+1) {
00144       if (argv[arg_index+1] != 0) {
00145         result = argv[arg_index+1];
00146       }
00147     }
00148   }
00149 
00150   return(result);
00151 }
00152 
00153 void broadcast_string(MPI_Comm comm, int root, std::string& strg)
00154 {
00155 #ifdef FEI_SER
00156   return;
00157 #else
00158   int numprocs = 1, localproc = 0;
00159   MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
00160   MPI_Comm_rank(MPI_COMM_WORLD, &localproc);
00161   if (numprocs==1) {
00162     return;
00163   }
00164 
00165   if (localproc == root) {
00166     int length = strg.size();
00167     MPI_Bcast(&length, 1, MPI_INT, root, comm);
00168     char* cstr = const_cast<char*>(strg.c_str());
00169     MPI_Bcast(cstr, strg.size(), MPI_CHAR, root, comm);
00170   }
00171   else {
00172     int length;
00173     MPI_Bcast(&length, 1, MPI_INT, root, comm);
00174     char* charstr = new char[length+1];
00175     MPI_Bcast(charstr, length, MPI_CHAR, root, comm);
00176     charstr[length] = '\0';
00177     strg = charstr;
00178     delete [] charstr;
00179   }
00180 
00181   return;
00182 #endif
00183 }
00184 
00185 void read_file_lines_into_strings(const char* filename,
00186            std::vector<std::string>& file_contents)
00187 {
00188   FEI_IFSTREAM infile(filename);
00189   if (!infile) {
00190     FEI_OSTRINGSTREAM osstr;
00191     osstr << "fei_test_utils::read_file_lines_into_strings ERROR, couldn't open file '"
00192          << filename << "'";
00193     throw std::runtime_error(osstr.str());
00194   }
00195 
00196   file_contents.clear();
00197 
00198   std::string line;
00199 
00200   getline(infile, line);
00201   while(!infile.eof()) {
00202     file_contents.push_back(line);
00203 
00204     line.resize(0);
00205     getline(infile, line);
00206   }
00207 }
00208 
00209 int get_filename_and_read_input(int argc, char** argv,
00210          MPI_Comm comm, int localProc,
00211          std::vector<std::string>& stdstrings)
00212 {
00213   std::string filename;
00214   if (localProc == 0) {
00215     filename = construct_filename(argc, argv);
00216   }
00217 
00218   try {
00219     read_input_file(filename.c_str(), comm, stdstrings);
00220   }
00221   catch(std::runtime_error& exc) {
00222     fei::console_out() << exc.what() << FEI_ENDL;
00223     ERReturn(-1);
00224   }
00225 
00226   return(0);
00227 }
00228 
00229 void read_input_file(const char* filename,
00230           MPI_Comm comm,
00231           std::vector<std::string>& file_contents)
00232 {
00233   int localProc =0;
00234 #ifndef FEI_SER
00235   int numProcs = 1;
00236   MPI_Comm_rank(comm, &localProc);
00237   MPI_Comm_size(comm, &numProcs);
00238 #endif
00239 
00240   if (localProc == 0) {
00241     read_file_lines_into_strings(filename, file_contents);
00242 
00243 #ifndef FEI_SER
00244     if (numProcs > 1) {
00245       int num = file_contents.size();
00246 
00247       MPI_Bcast(&num, 1, MPI_INT, 0, comm);
00248 
00249       for(int j=0; j<num; ++j) {
00250         const char* cptr = file_contents[j].c_str();
00251         int length = strlen(cptr) + 1;
00252         MPI_Bcast(&length, 1, MPI_INT, 0, comm);
00253         MPI_Bcast((void*)cptr, length, MPI_CHAR, 0, comm);
00254       }
00255     }
00256 #endif
00257   }
00258 #ifndef FEI_SER
00259   else {//localProc != 0
00260     int num = -1;
00261     MPI_Bcast(&num, 1, MPI_INT, 0, comm);
00262 
00263     file_contents.resize(0);
00264 
00265     for(int j=0; j<num; ++j) {
00266       int length = 0;
00267       MPI_Bcast(&length, 1, MPI_INT, 0, comm);
00268       char* newstring = new char[length];
00269       MPI_Bcast(newstring, length, MPI_CHAR, 0, comm);
00270       std::string strg(newstring);
00271       file_contents.push_back(strg);
00272       delete [] newstring;
00273     }
00274   }
00275 #endif
00276 }
00277 
00278 double get_file_benchmark(const char* filename,
00279          const char* testname)
00280 {
00281   std::vector<std::string> file_contents;
00282   read_file_lines_into_strings(filename, file_contents);
00283 
00284   double file_benchmark = 0.0;
00285   int err2 = snl_fei::getDoubleParamValue(testname,
00286             file_contents,
00287             file_benchmark);
00288   if (err2 != 0) {
00289     throw std::runtime_error("fei_test_utils::get_file_benchmark failed to find named benchmark");
00290   }
00291 
00292   return(file_benchmark);
00293 }
00294 
00295 bool within_percentage_margin(double value1,
00296              double value2,
00297              unsigned margin)
00298 {
00299   double maxval = std::abs(value1) > std::abs(value2) ? std::abs(value1) : std::abs(value2);
00300   if (maxval < 1.e-14) {
00301     //They're both close enough to zero, return true without dividing.
00302     return(true);
00303   }
00304 
00305   double difference = std::abs(value2 - value1);
00306   double lhs = 100.0*(difference/maxval);
00307   double rhs = 1.0*margin;
00308   return( lhs <= rhs );
00309 }
00310 
00311 int whichArg(int argc, const char*const* argv, const char* findarg)
00312 {
00313   for(int i=0; i<argc; i++) {
00314     if (argv[i] != NULL) {
00315       if (strcmp(findarg, argv[i]) == 0) return(i);
00316     }
00317   }
00318   return(-1);
00319 }
00320 
00321 bool check_and_cout_test_result(std::string testname,
00322          double value,
00323          double file_value,
00324          unsigned margin)
00325 {
00326   bool result = within_percentage_margin(value, file_value, margin);
00327   FEI_COUT << testname << " " << value << " ";
00328   if (!result) {
00329     FEI_COUT << "NOT ";
00330   }
00331   FEI_COUT << "within "<<margin<<"% of file value " << file_value << ". ";
00332 
00333   if (result) {
00334     FEI_COUT << "passed."<<FEI_ENDL;
00335   }
00336   else {
00337     FEI_COUT << "FAILED."<<FEI_ENDL;
00338   }
00339   return(result);
00340 }
00341 
00342 std::string check_test_result(double value,
00343         double goldvalue,
00344         unsigned margin)
00345 {
00346   bool result = within_percentage_margin(value, goldvalue, margin);
00347   return( result ? "passed" : "FAILED");
00348 }
00349 
00350 int compare_with_file_benchmark(const char* name,
00351          double benchmark,
00352          const char* filename)
00353 {
00354   if (name == NULL) return(-1);
00355   int returnValue = 0;
00356 
00357 #if defined(FEI_PLATFORM) && defined(FEI_OPT_LEVEL)
00358 
00359   FEI_OSTRINGSTREAM testname;
00360   testname << name<<"_"<<FEI_PLATFORM<<"_"<<FEI_OPT_LEVEL;
00361 
00362   double file_benchmark = 0.0;
00363   bool file_benchmark_available = true;
00364   try {
00365     file_benchmark = get_file_benchmark(filename, testname.str().c_str());
00366   }
00367   catch (std::runtime_error& exc) {
00368     file_benchmark_available = false;
00369   }
00370 
00371   if (file_benchmark_available) {
00372     bool test_passed = check_and_cout_test_result(testname.str(),
00373                  benchmark,
00374                  file_benchmark,
00375                  10);
00376     returnValue = test_passed ? 0 : 1;
00377     if (returnValue != 0) {
00378       return(returnValue);
00379     }
00380   }
00381 
00382 #else
00383   FEI_COUT << "(compile with -DFEI_PLATFORM=<platform> -DFEI_OPT_LEVEL=<opt|dbg>)"<<FEI_ENDL;
00384 #endif
00385 
00386   return(returnValue);
00387 }
00388 
00389 int dirname(const char* name, char*& dir)
00390 {
00391   //given a string which is a file-name, create a new string 'dir' and
00392   //populate it with the directory-name, or file-name minus the last '/file'
00393   //section.
00394 
00395   int i, len = strlen(name);
00396   dir = new char[len];
00397   for(i=0; i<len; ++i) {
00398     dir[i] = name[i];
00399   }
00400 
00401   i = len-1;
00402   if (i > 1) {
00403     while(i>0) {
00404       if (dir[i] == '/') {
00405   dir[i] = '\0';
00406   break;
00407       }
00408       else {
00409   dir[i] = '\0';
00410   --i;
00411       }
00412     }
00413   }
00414 
00415   if (i==0) dir[i] = '.';
00416 
00417   return(0);
00418 }
00419 
00420 void print_args(int argc, char** argv){
00421     FEI_COUT << "argc: " << argc << FEI_ENDL;
00422 
00423     for(int i=0; i<argc; i++){
00424       if (argv[i] != NULL) {
00425         FEI_COUT << "argv["<<i<<"]: " << argv[i] << FEI_ENDL;
00426       }
00427     }
00428     FEI_COUT << FEI_ENDL;
00429 }
00430 
00431 int compareMatrices(fei::FillableMat& mat1, fei::FillableMat& mat2, double tol)
00432 {
00433   if (mat1 == mat2) return 0;
00434   FEI_COUT << "compareMatrices returned not-equal, tol=="<<tol << FEI_ENDL;
00435   return 1;
00436 }
00437 
00438 int readMatrix(const char* baseName, int np, fei::FillableMat& matrix)
00439 {
00440   for(int i=0; i<np; i++) {
00441     FEI_OSTRINGSTREAM fileName;
00442     fileName <<baseName<<"."<<np<<"."<<i;
00443     FEI_IFSTREAM infile(fileName.str().c_str());
00444 
00445     infile.setf(IOS_SCIENTIFIC, IOS_FLOATFIELD);
00446 
00447     int row, col, tmp, numRows, numCols;
00448     double value;
00449     infile >> numRows;
00450     infile >> numCols;
00451     infile >> tmp;
00452 
00453     infile >> row;
00454     while(!infile.eof()) {
00455       infile >> col;
00456       infile >> value;
00457 
00458       matrix.putCoef(row, col, value);
00459 
00460       infile >> row;
00461     }
00462   }
00463 
00464   return(0);
00465 }
00466 
00467 int readMatrix(const char* fileName, fei::FillableMat& matrix)
00468 {
00469   matrix.clear();
00470 
00471   FEI_IFSTREAM infile(fileName);
00472   if (!infile) {
00473     FEI_COUT << "ERROR opening file " << fileName << FEI_ENDL;
00474     return(1);
00475   }
00476 
00477   infile.setf(IOS_SCIENTIFIC, IOS_FLOATFIELD);
00478 
00479   int row, col, tmp, numRows, numCols;
00480   double value;
00481   infile >> numRows;
00482   infile >> numCols;
00483   infile >> tmp;
00484 
00485   infile >> row;
00486   while(!infile.eof()) {
00487     infile >> col;
00488     infile >> value;
00489 
00490     matrix.putCoef(row, col, value);
00491 
00492     infile >> row;
00493   }
00494 
00495   return(0);
00496 }
00497 
00498 int writeMatrix(const char* fileName, fei::FillableMat& matrix)
00499 {
00500   FEI_OFSTREAM outfile(fileName);
00501   if (!outfile) {
00502     FEI_COUT << "ERROR opening file " << fileName << FEI_ENDL;
00503     return(1);
00504   }
00505 
00506   outfile.setf(IOS_SCIENTIFIC, IOS_FLOATFIELD);
00507 
00508   outfile << matrix;
00509 
00510   return(0);
00511 }
00512 
00513 int copy_feiMatrix_to_FillableMat(fei::Matrix& feimat, fei::FillableMat& fmat)
00514 {
00515   fmat.clear();
00516 
00517   fei::SharedPtr<fei::VectorSpace> rowspace =
00518     feimat.getMatrixGraph()->getRowSpace();
00519 
00520   MPI_Comm comm = rowspace->getCommunicator();
00521   int localProc = fei::localProc(comm);
00522 
00523   std::vector<int> globalOffsets;
00524   rowspace->getGlobalIndexOffsets(globalOffsets);
00525   int numLocalRows = globalOffsets[localProc+1]-globalOffsets[localProc];
00526   int firstLocalRow = globalOffsets[localProc];
00527 
00528   for(int i=0; i<numLocalRows; ++i) {
00529     int row = firstLocalRow+i;
00530     int rowLen;
00531     feimat.getRowLength(row, rowLen);
00532 
00533     std::vector<int> colindices(rowLen);
00534     std::vector<double> coefs(rowLen);
00535 
00536     feimat.copyOutRow(row, rowLen, &coefs[0], &colindices[0]);
00537 
00538     fmat.putRow(row, &colindices[0], &coefs[0], rowLen);
00539   }
00540 
00541   return(0);
00542 }
00543 
00544 } //namespace fei_test_utils
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends