FilePlotter.cpp

Go to the documentation of this file.
00001 /* ****************************************************************** **
00002 **    OpenSees - Open System for Earthquake Engineering Simulation    **
00003 **          Pacific Earthquake Engineering Research Center            **
00004 **                                                                    **
00005 **                                                                    **
00006 ** (C) Copyright 1999, The Regents of the University of California    **
00007 ** All Rights Reserved.                                               **
00008 **                                                                    **
00009 ** Commercial use of this program without express permission of the   **
00010 ** University of California, Berkeley, is strictly prohibited.  See   **
00011 ** file 'COPYRIGHT'  in main directory for information on usage and   **
00012 ** redistribution,  and for a DISCLAIMER OF ALL WARRANTIES.           **
00013 **                                                                    **
00014 ** Developed by:                                                      **
00015 **   Frank McKenna (fmckenna@ce.berkeley.edu)                         **
00016 **   Gregory L. Fenves (fenves@ce.berkeley.edu)                       **
00017 **   Filip C. Filippou (filippou@ce.berkeley.edu)                     **
00018 **                                                                    **
00019 ** ****************************************************************** */
00020                                                                         
00021 // $Revision: 1.12 $
00022 // $Date: 2005/07/06 22:00:20 $
00023 // $Source: /usr/local/cvs/OpenSees/SRC/recorder/FilePlotter.cpp,v $
00024                                                                         
00025                                                                         
00026 // Written: fmk 
00027 // Created: 11/99
00028 //
00029 // Description: This file contains the class implementation for FilePlotter
00030 // FilePlotter is a class for building a Plane Frame model in an interpreted
00031 // enviroment. The constructor is used to add new commands to the interpreter,
00032 // these commands are also defined in this file.
00033 //
00034 // What: "@(#) FilePlotter.C, revA"
00035 
00036 
00037 #include <stdlib.h>
00038 #include <string.h>
00039 
00040 #include <fstream>
00041 using std::ifstream;
00042 
00043 #include <iomanip>
00044 using std::ios;
00045 
00046 #include <ctype.h>
00047 #include <ID.h>
00048 
00049 #ifdef _WGL
00050 #include <OpenGLRenderer.h>
00051 #elif _GLX
00052 #include <OpenGLRenderer.h>
00053 #else
00054 #include <X11Renderer.h>
00055 #endif
00056 
00057 #include <PlainMap.h>
00058 #include <Vector.h>
00059 
00060 #include "FilePlotter.h"
00061 
00062 FilePlotter::FilePlotter(const char *_fileName1, 
00063                          const char *windowTitle, 
00064                          int xLoc, int yLoc, int width, int height, double dT)
00065   :Recorder(RECORDER_TAGS_FilePlotter), 
00066    theMap(0), theRenderer(0), cols(0), deltaT(dT), nextTimeStampToRecord(0.0),
00067    data1a(0), data1b(0), data2a(0), data2b(0)
00068 {
00069 
00070   // create the window in which we plot on the screen
00071   theMap = new PlainMap();
00072 #ifdef _WGL
00073   theRenderer = new OpenGLRenderer(windowTitle, xLoc, yLoc, width, height, *theMap);
00074 #elif _GLX
00075   theRenderer = new OpenGLRenderer(windowTitle, xLoc, yLoc, width, height, *theMap);
00076 #else
00077   theRenderer = new X11Renderer(windowTitle, xLoc, yLoc, width, height, *theMap);
00078 #endif
00079   // set up for standard xy-plot - rendering in the xy plane at z =0
00080   theRenderer->setVRP(0.0, 0.0, 0.0); 
00081   theRenderer->setVPN(0.0, 0.0, 1.0);
00082   theRenderer->setVUP(0.0, 1.0, 0.0);
00083   theRenderer->setFillMode("wire");             // wire mode
00084   theRenderer->setProjectionMode("parallel");  // wire mode
00085   theRenderer->setPlaneDist(1.0, -1.0);
00086   theRenderer->setPRP(0.0, 0.0, 10.0);
00087   theRenderer->setPortWindow(-1.0, 1.0, -1.0, 1.0);  // use the whole window
00088 
00089   // copy the file name
00090   fileName1 = new char[strlen(_fileName1)+1];
00091   if (fileName1 == 0) {
00092     opserr << "FilePlotter::FilePlotter -- out of memory copying fileName1 " << endln;
00093   }
00094   strcpy(fileName1, _fileName1);    
00095 
00096   fileName2 = 0;
00097 }
00098 
00099 
00100 
00101 FilePlotter::FilePlotter(const char *_fileName1, 
00102                          const char *_fileName2, 
00103                          const char *windowTitle, 
00104                          int xLoc, int yLoc, int width, int height, double dT)
00105   :Recorder(RECORDER_TAGS_FilePlotter), 
00106    theMap(0), theRenderer(0), cols(0), deltaT(dT), nextTimeStampToRecord(0.0),
00107    data1a(0), data1b(0), data2a(0), data2b(0)
00108 {
00109 
00110   // create the window in which we plot on the screen
00111   theMap = new PlainMap();
00112 #ifdef _WGL
00113   theRenderer = new OpenGLRenderer(windowTitle, xLoc, yLoc, width, height, *theMap);
00114 #elif _GLX
00115   theRenderer = new OpenGLRenderer(windowTitle, xLoc, yLoc, width, height, *theMap);
00116 #else
00117   theRenderer = new X11Renderer(windowTitle, xLoc, yLoc, width, height, *theMap);
00118 #endif
00119   // set up for standard xy-plot - rendering in the xy plane at z =0
00120   theRenderer->setVRP(0.0, 0.0, 0.0); 
00121   theRenderer->setVPN(0.0, 0.0, 1.0);
00122   theRenderer->setVUP(0.0, 1.0, 0.0);
00123   theRenderer->setFillMode("wire");             // wire mode
00124   theRenderer->setProjectionMode("parallel");  // wire mode
00125   theRenderer->setPlaneDist(1.0, -1.0);
00126   theRenderer->setPRP(0.0, 0.0, 10.0);
00127   theRenderer->setPortWindow(-1.0, 1.0, -1.0, 1.0);  // use the whole window
00128 
00129   // copy the file name
00130   fileName1 = new char[strlen(_fileName1)+1];
00131   fileName2 = new char[strlen(_fileName2)+1];
00132   if (fileName1 == 0 || fileName2 == 0) {
00133     opserr << "FilePlotter::FilePlotter -- out of memory copying fileName1 " << endln;
00134   }
00135   strcpy(fileName1, _fileName1);    
00136   strcpy(fileName2, _fileName2);    
00137 }
00138 
00139 FilePlotter::~FilePlotter()
00140 {
00141   // may possibly invoke Tcl_DeleteCommand() later
00142   // for moment just invoke destructor on map and renderer
00143   // and set pointer to NULL
00144   delete theMap;
00145   delete theRenderer;
00146 
00147   if (cols != 0)
00148     delete cols;
00149 
00150   if (fileName1 != 0)
00151     delete [] fileName1;
00152 
00153   if (fileName2 != 0)
00154     delete [] fileName2;
00155 
00156   if (data1a != 0)
00157     delete data1a;
00158   if (data1b != 0)
00159     delete data1b;
00160   if (data2a != 0)
00161     delete data2a;
00162   if (data2b != 0)
00163     delete data2b;
00164 }
00165     
00166 int 
00167 FilePlotter::record(int cTag, double timeStamp)
00168 {
00169 
00170   if (deltaT == 0.0 || timeStamp >= nextTimeStampToRecord) {
00171 
00172     if (deltaT != 0.0) 
00173       nextTimeStampToRecord = timeStamp + deltaT;
00174 
00175     if (fileName1 != 0 && fileName2 == 0)
00176       return this->plotFile();
00177     else if (fileName1 != 0 && fileName2 != 0)
00178       return this->plotFiles();      
00179     else 
00180       return 0;
00181 
00182   } else
00183     return 0;
00184 }
00185 
00186 int 
00187 FilePlotter::playback(int cTag)
00188 {
00189   //  this->plotFile();
00190   return 0;
00191 }
00192 
00193 int
00194 FilePlotter::restart(void)
00195 {
00196   return 0;
00197 }
00198 
00199 int
00200 FilePlotter::setFile(char *newFileName)
00201 {
00202   strcpy(fileName1, newFileName);    
00203   return 0;
00204 }
00205 
00206 int
00207 FilePlotter::plotFile(void)
00208 {
00209     /*
00210      * first pass: 1) open file
00211      *             2) determine number of entries on first line ASSSSSUME same through file
00212      *             3) determine number of lines and bounds [xmin, xmax, ymin, ymax]
00213      *             4) close the file
00214      */
00215   
00216      // open file
00217     ifstream theFile; 
00218     theFile.open(fileName1, ios::in);
00219 
00220     if (theFile.bad()) {
00221         opserr << "WARNING - FilePlotter::FilePlotter()";
00222         opserr << " - could not open file " << fileName1 << endln;
00223         return -1;
00224     }    
00225 
00226     double xMin, xMax, yMin, yMax;
00227     xMin = 0; xMax = 0; yMin =0; yMax =0;
00228     double xValue, yValue;
00229 
00230     // determine number of elements in each line 
00231     //  NOTE ASSUMES ALL LINES HAVE THE SAME NUMBER OF ELEMENTS
00232     char c;
00233     int numLineEntries = 0;
00234     int numLines = 0;
00235 
00236     while (theFile.get(c) && (c!= EOF) && c != '\n') {
00237       if (!isspace(c)) {
00238         theFile.putback(c);
00239 
00240         theFile >> xValue;
00241         for (int i=0; i<cols->Size(); i++) {
00242           if (i%2 == 0) { // an xValue if numLineEntries == colX
00243             if (numLineEntries == (*cols)(i)) {
00244               if (xValue < xMin) xMin = xValue;
00245               if (xValue > xMax) xMax = xValue;
00246             }
00247           } else { // a y value if (numLineEntries == colY) {
00248             if (numLineEntries == (*cols)(i)) {
00249               if (xValue < yMin) yMin = xValue;
00250               if (xValue > yMax) yMax = xValue;   
00251             } 
00252           }
00253         }
00254         
00255 
00256         numLineEntries ++;
00257       }
00258       numLines =1;
00259     }
00260 
00261 
00262     if (data1a == 0 || data1b == 0 || 
00263         data1a->Size() != numLineEntries || data1b->Size() != numLineEntries) {
00264       if (data1a != 0) delete data1a;
00265       if (data1b != 0) delete data1b;
00266       
00267       data1a = new Vector(numLineEntries);
00268       data1b = new Vector(numLineEntries);
00269     }
00270 
00271     // check colX and colY for valid entries
00272     if (numLines > 0) {
00273       if (cols == 0) {
00274         opserr << "FilePLotter::plotFile() - no valid columns have been set\n";
00275 
00276       } else {
00277 
00278         // parse through file checking the bounds
00279         Vector data(numLineEntries);
00280         while (theFile >> (*data1a)(0)) {
00281           for (int j=1; j<numLineEntries; j++)
00282             theFile >> (*data1a)(j);
00283 
00284           for (int i=0; i<cols->Size(); i += 2) {
00285             xValue = (*data1a)((*cols)(i));
00286             yValue = (*data1a)((*cols)(i+1));
00287             if (xValue < xMin) xMin = xValue;
00288             if (xValue > xMax) xMax = xValue;
00289             if (yValue < yMin) yMin = yValue;
00290             if (yValue > yMax) yMax = yValue;
00291             numLines++;
00292           }    
00293         }
00294 
00295         // set the window bounds NOTE small border around the edges
00296         double xBnd = (xMax-xMin)/8;
00297         double yBnd = (yMax-yMin)/8;
00298     
00299         theRenderer->setViewWindow(xMin-xBnd,xMax+xBnd,yMin-yBnd,yMax+yBnd);
00300       }
00301     }
00302 
00303     // close the file
00304     theFile.close();
00305 
00306     /*
00307      * second pass: 1) open file
00308      *              2) get the renderer ready for drawing virgin image and then draw the x and y axis
00309      *              3) parse throgh the file and connect the dots
00310      *              4) close the file
00311      */
00312 
00313     if (numLines > 1) {
00314 
00315       static Vector pt1(3); 
00316       static Vector pt2(3);
00317       static Vector rgb(3);
00318 
00319       // clear the present image and get renderer ready to process data
00320       theRenderer->clearImage();
00321       theRenderer->startImage();
00322 
00323       // draw the x axis
00324       pt1(0) = xMin; pt2(0) = xMax;
00325       pt1(1) = 0.0;  pt2(1) = 0.0;
00326       theRenderer->drawLine(pt1, pt2, rgb, rgb);    
00327 
00328       static char theText[20];
00329       if (xMin != 0.0 && -100*xMin > xMax) {
00330         sprintf(theText,"%.2e",xMin);
00331         theRenderer->drawText(pt1, theText, strlen(theText), 'l', 'b');
00332       }
00333       if (xMax != 0.0) {
00334         sprintf(theText,"%.2e",xMax);
00335         theRenderer->drawText(pt2, theText, strlen(theText), 'r', 'b');
00336       }
00337 
00338       // draw the y axis
00339       pt1(0) = 0.0; pt2(0) = 0.0;
00340       pt1(1) = yMin;  pt2(1) = yMax;
00341       theRenderer->drawLine(pt1, pt2, rgb, rgb);        
00342 
00343       if (yMin != 0.0 && -100 *yMin > yMax) {
00344         sprintf(theText,"%.2e",yMin);
00345         theRenderer->drawText(pt1, theText, strlen(theText), 'c', 't');
00346       }
00347       if (yMax != 0.0) {
00348         sprintf(theText,"%.2e",yMax);
00349         theRenderer->drawText(pt2, theText, strlen(theText), 'c', 'b');
00350       }
00351 
00352       // open the file again, read through and connect the dots
00353       ifstream theFile1; 
00354       theFile1.open(fileName1, ios::in);
00355       if (theFile1.bad()) {
00356         opserr << "WARNING - FilePlotter::FilePlotter()";
00357         opserr << " - could not open file " << fileName1 << endln;
00358         return -1;
00359       }    
00360 
00361       for (int ii=0; ii< numLineEntries; ii++)
00362         theFile1 >> (*data1a)(ii);
00363 
00364       for (int i=1; i<numLines; i++) {
00365         // read the data
00366         for (int ii=0; ii< numLineEntries; ii++)
00367           theFile1 >> (*data1b)(ii);
00368 
00369         // plot the lines
00370         for (int j=0; j<cols->Size(); j+=2) {
00371           pt1(0) = (*data1a)((*cols)(j)); 
00372           pt1(1) = (*data1a)((*cols)(j+1));
00373           pt2(0) = (*data1b)((*cols)(j)); 
00374           pt2(1) = (*data1b)((*cols)(j+1));
00375           theRenderer->drawLine(pt1, pt2, rgb, rgb);
00376         }
00377         
00378         *data1a = *data1b;
00379 
00380       }
00381       
00382       theRenderer->doneImage();
00383 
00384       // close the file
00385       theFile1.close();
00386 
00387     }
00388     return 0;
00389 }
00390 
00391 
00392 
00393 int
00394 FilePlotter::plotFiles(void)
00395 {
00396     /*
00397      * first pass: 1) open files
00398      *             2) determine number of entries on first line ASSSSSUME same through file
00399      *             3) determine number of lines and bounds [xmin, xmax, ymin, ymax]
00400      *             4) close the file
00401      */
00402   
00403      // open file
00404     ifstream theXfile; 
00405     theXfile.open(fileName1, ios::in);
00406 
00407     ifstream theYfile; 
00408     theYfile.open(fileName2, ios::in);
00409 
00410     if (theXfile.bad() || theYfile.bad()) {
00411         opserr << "WARNING - FilePlotter::FilePlotter()";
00412         opserr << " - could not open files " << fileName1 << " " << fileName2 << endln;
00413         return -1;
00414     }    
00415 
00416     double xMin, xMax, yMin, yMax;
00417     xMin = 0; xMax = 0; yMin =0; yMax =0;
00418     double xValue, yValue;
00419 
00420     // determine number of elements in each line 
00421     //  NOTE ASSUMES ALL LINES HAVE THE SAME NUMBER OF ELEMENTS
00422     char c;
00423     int numLineEntriesX = 0;
00424     int numLineEntriesY = 0;
00425     int numLinesX = 0;
00426     int numLinesY = 0;
00427 
00428     while (theXfile.get(c) && (c!= EOF) && c != '\n') {
00429       if (!isspace(c)) {
00430         theXfile.putback(c);
00431 
00432         theXfile >> xValue;
00433         for (int i=0; i<cols->Size(); i++) {
00434           if (i%2 == 0) { // an xValue if numLineEntries == colX
00435             if (numLineEntriesX == (*cols)(i)) {
00436               if (xValue < xMin) xMin = xValue;
00437               if (xValue > xMax) xMax = xValue;
00438             }
00439           }
00440         }
00441         numLineEntriesX ++;
00442       }
00443       numLinesX =1;
00444     }
00445 
00446     while (theYfile.get(c) && (c!= EOF) && c != '\n') {
00447       if (!isspace(c)) {
00448         theYfile.putback(c);
00449 
00450         theYfile >> yValue;
00451         for (int i=0; i<cols->Size(); i++) {
00452           if (i%2 != 0) { // a yValue
00453             if (numLineEntriesY == (*cols)(i)) {
00454               if (yValue < yMin) yMin = yValue;
00455               if (yValue > yMax) yMax = yValue;
00456             }
00457           }
00458         }
00459         numLineEntriesY ++;
00460       }
00461       numLinesY =1;
00462     }
00463 
00464 
00465     if (data1a == 0 || data1b == 0 || 
00466         data1a->Size() != numLineEntriesX || data1b->Size() != numLineEntriesX ||
00467         data2a == 0 || data2b == 0 || 
00468         data2a->Size() != numLineEntriesY || data2b->Size() != numLineEntriesY) {
00469 
00470       if (data1a != 0) delete data1a;
00471       if (data1b != 0) delete data1b;
00472       if (data2a != 0) delete data2a;
00473       if (data2b != 0) delete data2b;
00474       
00475       data1a = new Vector(numLineEntriesX);
00476       data1b = new Vector(numLineEntriesX);
00477       data2a = new Vector(numLineEntriesY);
00478       data2b = new Vector(numLineEntriesY);
00479     }
00480 
00481     // check colX and colY for valid entries
00482     if (numLinesX > 0 && numLinesY > 0) {
00483       if (cols == 0) {
00484         opserr << "FilePLotter::plotFile() - no valid columns have been set\n";
00485         return 0;
00486       } else {
00487 
00488         // parse through file checking the bounds
00489         while (theXfile >> (*data1a)(0)) {
00490           for (int j=1; j<numLineEntriesX; j++)
00491             theXfile >> (*data1a)(j);
00492           
00493           for (int i=0; i<cols->Size(); i += 2) {
00494             xValue = (*data1a)((*cols)(i));
00495             if (xValue < xMin) xMin = xValue;
00496             if (xValue > xMax) xMax = xValue;
00497             numLinesX++;
00498           }    
00499         }
00500 
00501         while (theYfile >> (*data2a)(0)) {
00502           for (int j=1; j<numLineEntriesY; j++)
00503             theYfile >> (*data2a)(j);
00504           
00505           for (int i=0; i<cols->Size(); i += 2) {
00506             yValue = (*data2a)((*cols)(i+1));
00507             if (yValue < yMin) yMin = yValue;
00508             if (yValue > yMax) yMax = yValue;
00509             numLinesY++;
00510           }    
00511         }
00512 
00513         // set the window bounds NOTE small border around the edges
00514         double xBnd = (xMax-xMin)/8;
00515         double yBnd = (yMax-yMin)/8;
00516     
00517         theRenderer->setViewWindow(xMin-xBnd,xMax+xBnd,yMin-yBnd,yMax+yBnd);
00518       }
00519     }
00520 
00521     // close the file
00522     theXfile.close();
00523     theYfile.close();
00524 
00525 
00526     if (numLinesX != numLinesY) {
00527         opserr << "FilePLotter::plotFile() - two files have different line counts\n";
00528         return -1;
00529     }
00530 
00531     /*
00532      * second pass: 1) open file
00533      *              2) get the renderer ready for drawing virgin image and then draw the x and y axis
00534      *              3) parse throgh the file and connect the dots
00535      *              4) close the file
00536      */
00537 
00538     if (numLinesX > 1) {
00539 
00540       static Vector pt1(3); 
00541       static Vector pt2(3);
00542       static Vector rgb(3);
00543 
00544       // clear the present image and get renderer ready to process data
00545       theRenderer->clearImage();
00546       theRenderer->startImage();
00547 
00548       // draw the x axis
00549       pt1(0) = xMin; pt2(0) = xMax;
00550       pt1(1) = 0.0;  pt2(1) = 0.0;
00551       theRenderer->drawLine(pt1, pt2, rgb, rgb);    
00552 
00553       static char theText[20];
00554       if (xMin != 0.0 && -100*xMin > xMax) {
00555         sprintf(theText,"%.2e",xMin);
00556         theRenderer->drawText(pt1, theText, strlen(theText), 'l', 'b');
00557       }
00558       if (xMax != 0.0) {
00559         sprintf(theText,"%.2e",xMax);
00560         theRenderer->drawText(pt2, theText, strlen(theText), 'r', 'b');
00561       }
00562 
00563       // draw the y axis
00564       pt1(0) = 0.0; pt2(0) = 0.0;
00565       pt1(1) = yMin;  pt2(1) = yMax;
00566       theRenderer->drawLine(pt1, pt2, rgb, rgb);        
00567 
00568       if (yMin != 0.0 && -100 *yMin > yMax) {
00569         sprintf(theText,"%.2e",yMin);
00570         theRenderer->drawText(pt1, theText, strlen(theText), 'c', 't');
00571       }
00572       if (yMax != 0.0) {
00573         sprintf(theText,"%.2e",yMax);
00574         theRenderer->drawText(pt2, theText, strlen(theText), 'c', 'b');
00575       }
00576 
00577       // open the file again, read through and connect the dots
00578       ifstream theXfile1; 
00579       theXfile1.open(fileName1, ios::in);
00580       ifstream theYfile1; 
00581       theYfile1.open(fileName1, ios::in);
00582 
00583       if (theXfile1.bad() || theYfile1.bad()) {
00584         opserr << "WARNING - FilePlotter::FilePlotter()";
00585         opserr << " - could not open files " << fileName1 << " " << fileName2 << endln;
00586         return -1;
00587       }    
00588 
00589       for (int ii=0; ii< numLineEntriesX; ii++)
00590         theXfile1 >> (*data1a)(ii);
00591 
00592       for (int jj=0; jj< numLineEntriesY; jj++)
00593         theYfile1 >> (*data2a)(jj);
00594 
00595       for (int i=1; i<numLinesX; i++) {
00596         // read the data
00597         for (int ii=0; ii< numLineEntriesX; ii++)
00598           theXfile1 >> (*data1b)(ii);
00599         for (int kk=0; kk< numLineEntriesY; kk++)
00600           theYfile1 >> (*data2b)(kk);
00601 
00602         // plot the lines
00603         for (int j=0; j<cols->Size(); j+=2) {
00604           pt1(0) = (*data1a)((*cols)(j)); 
00605           pt1(1) = (*data2a)((*cols)(j+1));
00606           pt2(0) = (*data1b)((*cols)(j)); 
00607           pt2(1) = (*data2b)((*cols)(j+1));
00608           theRenderer->drawLine(pt1, pt2, rgb, rgb);
00609         }
00610         
00611         *data1a = *data1b;
00612         *data2a = *data2b;
00613       }
00614       
00615       theRenderer->doneImage();
00616 
00617       // close the file
00618       theXfile1.close();
00619       theYfile1.close();
00620 
00621     }
00622     return 0;
00623 }
00624 
00625 
00626 int
00627 FilePlotter::setCol(const ID &theCols)
00628 {
00629   if (theCols.Size()%2 != 0) {
00630     opserr << "FilePlotter::setCol() - the size of the cols ID " << theCols.Size() << " is not a multiple of 2\n";
00631     return -1;
00632   }
00633 
00634   for (int i=0; i<theCols.Size(); i++) {
00635     if (theCols(i) < 1) {
00636       opserr << "FilePlotter::FilePlotter() - a value of the cols " << theCols(i) << " is < 1\n";
00637       return -2;
00638     }
00639   }
00640   // check colX is valid, i.e. >= 1
00641   // if valid set colX using c indexing
00642 
00643   if (cols != 0) {
00644     if (cols->Size() != theCols.Size()) {
00645       delete cols;
00646       cols = 0;
00647     } else
00648       *cols = theCols;
00649   }
00650 
00651   if (cols == 0)
00652     cols = new ID(theCols);
00653 
00654   for (int j=0; j<cols->Size(); j++)
00655     (*cols)(j) -= 1;
00656     
00657   return 0;
00658 }
00659 
00660 
00661 
00662 
00663 
00664 
00665 

Generated on Mon Oct 23 15:05:24 2006 for OpenSees by doxygen 1.5.0