libMems/ClustalInterface.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002  * $Id: ClustalInterface.cpp,v 1.27 2004/03/01 02:40:08 darling Exp $
00003  * This file is copyright 2002-2007 Aaron Darling and authors listed in the AUTHORS file.
00004  * Please see the file called COPYING for licensing, copying, and modification
00005  * Please see the file called COPYING for licensing details.
00006  * **************
00007  ******************************************************************************/
00008 
00009 #ifdef HAVE_CONFIG_H
00010 #include "config.h"
00011 #endif
00012 
00013 #include "libMems/ClustalInterface.h"
00014 #include <sstream>
00015 #include "libGenome/gnFilter.h"
00016 
00017 #include <fstream>
00018 
00019 extern "C" {
00020 #include "libClustalW/clustalw.h"
00021 
00022 extern sint max_names;
00023 extern Boolean usemenu, dnaflag, explicit_dnaflag;
00024 extern Boolean interactive;
00025 extern char *seqname;
00026 extern sint nseqs;
00027 extern sint *seqlen_array;
00028 extern char **names,**titles;
00029 extern char **seq_array;
00030 //extern Boolean profile1_empty, profile2_empty;
00031 extern sint max_aln_length;
00032 //extern char *gap_penalty_mask, *sec_struct_mask;
00033 //extern sint struct_penalties;
00034 extern float    gap_open,      gap_extend;
00035 extern float    dna_gap_open,  dna_gap_extend;
00036 //extern char *gap_penalty_mask1,*gap_penalty_mask2;
00037 //extern char *sec_struct_mask1,*sec_struct_mask2;
00038 //extern sint struct_penalties1,struct_penalties2;
00039 //extern char *ss_name1,*ss_name2;
00040 extern float    pw_go_penalty,      pw_ge_penalty;
00041 extern float    dna_pw_go_penalty,  dna_pw_ge_penalty;
00042 //extern sint    wind_gap,ktup,window,signif;
00043 //extern sint    dna_wind_gap, dna_ktup, dna_window, dna_signif;
00044 
00045 extern Boolean  output_clustal, output_nbrf, output_phylip, output_gcg, output_gde, output_nexus;
00046 extern FILE     *clustal_outfile, *gcg_outfile, *nbrf_outfile, *phylip_outfile, *nexus_outfile;
00047 //extern char   clustal_outname[FILENAMELEN+1], gcg_outname[FILENAMELEN+1];
00048 extern char* amino_acid_codes;
00049 extern sint max_aa;
00050 
00051 //extern short   blosum45mt[];
00052 //extern short   def_aa_xref[];
00053 extern sint gap_pos1;
00054 extern double** tmat;
00055 
00056 extern Boolean          use_endgaps;
00057 extern Boolean          endgappenalties;
00058 
00059 extern sint output_order;
00060 extern Boolean  no_weights;
00061 
00062 }
00063 
00064 using namespace std;
00065 using namespace genome;
00066 namespace mems {
00067 
00074 #define MISALIGNMENT_WORKAROUND
00075 
00076 lint get_aln_score(void);
00077 
00078 
00079 ClustalInterface& ClustalInterface::getClustalInterface()
00080 {
00081         static ClustalInterface m_ci;
00082 
00083         return m_ci;
00084 }
00085 
00086 ClustalInterface::ClustalInterface(){
00087         // some defaults can't hurt
00088         max_alignment_length = 10000;
00089         min_flank_size = 3;
00090         clustal_score_cutoff = 0;
00091 
00092         // shut off end gaps...
00093         use_endgaps = FALSE;
00094         // enable end gap penalties
00095         endgappenalties = TRUE;
00096         // force same input/output order
00097         output_order = INPUT;
00098         no_weights = FALSE; // TRUE;
00099 
00100 
00101         init_amenu();
00102         init_interface();
00103         init_matrix();
00104 
00105         fill_chartab();
00106         allocated_aln = false;
00107         
00108         // shut off end gaps...
00109         use_endgaps = FALSE;
00110         // enable end gap penalties
00111         endgappenalties = TRUE;
00112 }
00113 
00114 ClustalInterface& ClustalInterface::operator=( const ClustalInterface& ci )
00115 {
00116         GappedAligner::operator=( ci );
00117         min_flank_size = ci.min_flank_size;
00118         clustal_score_cutoff = ci.clustal_score_cutoff;
00119         distance_matrix = ci.distance_matrix;
00120         allocated_aln = ci.allocated_aln;
00121         return *this;
00122 }
00123 
00124 void ClustalInterface::SetDistanceMatrix( NumericMatrix< double >& distance_matrix, string& tree_filename ){
00125         SetDistanceMatrix( distance_matrix, tree_filename, false );
00126 }
00127 
00128 void ClustalInterface::SetDistanceMatrix( NumericMatrix< double >& distance_matrix, string& tree_filename, boolean reread_tree ){
00129         char* phylip_name;
00130         uint seqI, seqJ;
00131 #ifdef MISALIGNMENT_WORKAROUND
00132         if( reread_tree == false ){
00133                 NumericMatrix< double > dist_plus_matrix( distance_matrix.cols() + 1, distance_matrix.cols() + 1 );
00134                 for( seqI = 0; seqI < dist_plus_matrix.cols(); seqI++ ){
00135                         for( seqJ = 0; seqJ < dist_plus_matrix.cols(); seqJ++ ){
00136                                 double new_val = 0;
00137                                 if( seqI == 0 ){
00138                                         if( seqJ == 0 )
00139                                                 new_val = 0;
00140                                         else
00141                                                 new_val = distance_matrix( seqI, seqJ - 1 );
00142                                 }else{
00143                                         if( seqJ == 0 )
00144                                                 new_val = distance_matrix( seqI - 1, seqJ );
00145                                         else
00146                                                 new_val = distance_matrix( seqI - 1, seqJ - 1 );
00147                                 }
00148                                 dist_plus_matrix( seqI, seqJ ) = new_val;
00149                         }
00150                 }
00151                 SetDistanceMatrix( dist_plus_matrix, tree_filename, true );
00152         }
00153 #else
00154         reread_tree = true;
00155 #endif
00156         if( reread_tree )
00157                 this->distance_matrix = distance_matrix;
00158         free_aln( nseqs );
00159         nseqs = distance_matrix.cols();
00160         alloc_aln( nseqs );
00161         allocated_aln = true;
00162 
00163         for( seqI = 1; seqI <= distance_matrix.cols(); seqI++ ){
00164                 ostringstream ss;
00165                 ss << "seq" << seqI;
00166                 int namelen = MAXNAMES < ss.str().size() ? MAXNAMES : ss.str().size();
00167                 strncpy( names[ seqI ], ss.str().c_str(), namelen);             /*    "   "  name   */
00168                 strncpy( titles[ seqI ], ss.str().c_str(), namelen);            /*    "   "  title  */
00169 
00170                 alloc_seq( seqI, 1 );
00171                 // set max_names and max_aln_length
00172                 if( strlen( names[ seqI ] ) > max_names )
00173                         max_names = strlen( names[ seqI ] );
00174         }
00175         // copy phylo tree name
00176         phylip_name = (char * ) ckalloc( tree_filename.length() + 1);
00177         strcpy( phylip_name, tree_filename.c_str() );
00178         
00179         // copy tmat entries
00180         for( seqI = 0; seqI < nseqs; seqI++ )
00181                 for( uint seqJ = 0; seqJ < nseqs; seqJ++ )
00182                         tmat[ seqI + 1][ seqJ + 1 ] = distance_matrix( seqI, seqJ );
00183         
00184         FILE* tree;
00185         if((tree = open_explicit_file( phylip_name ))==NULL) return;
00186         if (nseqs >= 2) {
00187                 guide_tree(tree,1,nseqs);
00188         }
00189 
00190 
00191 // read the tree back in
00192         if( reread_tree )
00193                 int status = read_tree(phylip_name, (sint)0, nseqs);
00194         phylip_name = (char*)ckfree( phylip_name );
00195         allocated_aln = false;
00196 
00197 }
00198 
00199 // tries to read in a guide tree from a particular file,
00200 // throws an exception if it doesn't work out
00201 void ClustalInterface::setGuideTree( string& tree_filename, NumericMatrix< double >& dist_mat, uint seq_count ){
00202 #ifdef MISALIGNMENT_WORKAROUND
00203         seq_count++;
00204 #endif
00205         distance_matrix = dist_mat;
00206         // check whether the file exists
00207         ifstream guide_file( tree_filename.c_str() );
00208         if( guide_file.is_open() )
00209                 guide_file.close();     // success
00210         else
00211                 throw( "Unable to open guide tree file" );
00212 
00213         char* phylip_name;
00214         uint seqI;
00215 
00216         free_aln( nseqs );
00217         nseqs = seq_count;
00218         alloc_aln( nseqs );
00219         allocated_aln = true;
00220 
00221         for( seqI = 1; seqI <= seq_count; seqI++ ){
00222                 ostringstream ss;
00223                 ss << "seq" << seqI;
00224                 int namelen = MAXNAMES < ss.str().size() ? MAXNAMES : ss.str().size();
00225                 strncpy( names[ seqI ], ss.str().c_str(), namelen);             /*    "   "  name   */
00226                 strncpy( titles[ seqI ], ss.str().c_str(), namelen);            /*    "   "  title  */
00227 
00228                 alloc_seq( seqI, 1 );
00229                 // set max_names and max_aln_length
00230                 if( strlen( names[ seqI ] ) > max_names )
00231                         max_names = strlen( names[ seqI ] );
00232         }
00233 
00234         // copy tmat entries
00235         for( seqI = 0; seqI < nseqs; seqI++ )
00236                 for( uint seqJ = 0; seqJ < nseqs; seqJ++ )
00237                         tmat[ seqI + 1][ seqJ + 1 ] = 1 - distance_matrix( seqI, seqJ );
00238 
00239         // copy phylo tree name
00240         phylip_name = (char * ) ckalloc( tree_filename.length() + 1);
00241         strcpy( phylip_name, tree_filename.c_str() );
00242         int success = read_tree(phylip_name, (sint)0, nseqs);
00243         phylip_name = (char*)ckfree( phylip_name );
00244         allocated_aln = false;
00245         if( !success )
00246                 throw "Error loading guide tree\n";
00247 }
00248 
00249 boolean ClustalInterface::Align( GappedAlignment& cr, Match* r_begin, Match* r_end, vector< gnSequence* >& seq_table ){
00250         boolean flank = false;
00251         gnSeqI gap_size = 0;
00252         boolean create_ok = true;
00253         uint seq_count = seq_table.size();
00254         uint seqI;
00255         uint align_seqs = 0;
00256 //      
00257 //  get the size of the largest intervening gap
00258 //  also do some sanity checking while we're at it.
00259 //
00260 try{
00261         for( seqI = 0; seqI < seq_count; seqI++ ){
00262                 int64 gap_start = 0;
00263                 int64 gap_end = 0;
00264                 create_ok = getInterveningCoordinates( seq_table, r_begin, r_end, seqI, gap_start, gap_end );
00265                 // skip this sequence if it's undefined
00266                 if( gap_start == NO_MATCH || gap_end == NO_MATCH )
00267                         continue;
00268                 if( !create_ok )
00269                         break;
00270 
00271                 int64 diff = gap_end - gap_start;
00272                 if( diff <= 0 ){
00273                         continue;       // can't align nothing
00274                 }
00275                 if( diff > max_alignment_length ){
00276                         cout << "gap from " << gap_start << " to " << gap_end << " is too big for ClustalW\n";
00277                         continue;       // can't align if it's too big
00278                 }
00279                 gap_size = diff < gap_size ? gap_size : diff;
00280                 align_seqs++;
00281         }
00282 
00283         if( align_seqs <= 1 )
00284                 create_ok = false;
00285 // 
00286 //      Get the sequence in the intervening gaps between these two matches
00287 //  Include a flank of matching sequence on either side
00288 //
00289         vector< string > seq_data;
00290         vector< int64 > starts;
00291         gnSeqI left_flank, right_flank;
00292         const gnFilter* rc_filter = gnFilter::DNAComplementFilter();
00293 
00294         if( create_ok ){
00295 //              left_flank = min( r_begin->Length(), max( gap_size, min_flank_size ) );
00296 //              right_flank = min( r_end->Length(), max( gap_size, min_flank_size ) );
00297                 left_flank = 0;
00298                 right_flank = 0;
00299                 
00300                 for( seqI = 0; seqI < seq_count; seqI++ ){
00301                         // cheap hack to avoid mysterious clustalW misalignment
00302 #ifdef MISALIGNMENT_WORKAROUND
00303                         if( seqI == 1 )
00304                                 seq_data.push_back( seq_data[ 0 ] );
00305 #endif
00306                         // skip this sequence if it's undefined
00307                         if( (r_end != NULL && r_end->Start( seqI ) == NO_MATCH ) ||
00308                                 (r_begin != NULL && r_begin->Start( seqI ) == NO_MATCH) ){
00309                                 starts.push_back( NO_MATCH );
00310                                 seq_data.push_back( "" );
00311                                 continue;
00312                         }
00313 
00314                         // determine the size of the gap
00315                         int64 gap_start = 0;
00316                         int64 gap_end = 0;
00317                         getInterveningCoordinates( seq_table, r_begin, r_end, seqI, gap_start, gap_end );
00318 
00319                         int64 diff = gap_end - gap_start;
00320                         if( diff <= 0 || diff > max_alignment_length ){
00321                                 starts.push_back( NO_MATCH );
00322                                 seq_data.push_back( "" );
00323                                 continue;
00324                         }
00325                         // calculate flank size and extract sequence data
00326                         if( r_end == NULL || r_end->Start( seqI ) > 0 ){
00327                                 starts.push_back( gap_start );
00328                                 seq_data.push_back( seq_table[ seqI ]->ToString( left_flank + diff + right_flank, gap_start - left_flank ) );
00329                         }else{
00330                                 // reverse complement the sequence data.
00331                                 starts.push_back( -gap_start );
00332                                 string cur_seq_data = seq_table[ seqI ]->ToString( left_flank + diff + right_flank, gap_start - right_flank );
00333                                 rc_filter->ReverseFilter( cur_seq_data );
00334                                 seq_data.push_back( cur_seq_data );
00335                         }
00336                 }
00337         }
00338 
00339         if( create_ok ){
00340                 if( !CallClustal( seq_data ) ){
00341                         cout << "Clustal was unable to align:\n";
00342                         cout << "Left match: " << *r_begin << endl;
00343                         cout << "Right match: " << *r_end << endl;
00344                         return false;
00345                 }
00346 
00347                 // ensure that the flanks were successfully aligned
00348                 boolean good_alignment = true;
00349                 gnSeqI flankI = 0;
00350                 gnSeqI align_length=0;
00351                 for( seqI = 1; seqI <= seq_count; seqI++ )
00352                         if( align_length < ( seqlen_array[seqI] < 0 ? 0 : (gnSeqI)seqlen_array[seqI] ))
00353                                 align_length = seqlen_array[seqI];
00354 
00355                 if( !good_alignment ){
00356                         // just align without the flanking regions for now??
00357                         return false;
00358                 }else{
00359                         // now extract the alignment from clustal's global variables
00360                         cr = GappedAlignment( seq_count, align_length );
00361                         vector< string > align_array;
00362                         int64 last_residue = -1;        // tracks the right-most residue in the alignment
00363                         int64 first_residue = align_length + 2; // tracks the left-most residue in the alignment
00364 #ifdef MISALIGNMENT_WORKAROUND
00365                         for( seqI = 2; seqI <= seq_count + 1; seqI++ ){
00366 #else
00367                         for( seqI = 1; seqI <= seq_count; seqI++ ){
00368 #endif
00369                                 string new_seq = string( seqlen_array[ seqI ] - left_flank - right_flank, '-' );
00370                                 uint new_seq_charI = 0;
00371                                 uint cur_seq_len = 0;
00372                                 for( uint charJ = left_flank + 1; charJ <= seqlen_array[ seqI ] - right_flank; charJ++ ){
00373                                         char val = seq_array[ seqI ][ charJ ];
00374                                         if( val >= 0 && val <= max_aa ){
00375                                                 if( charJ > last_residue )
00376                                                         last_residue = charJ;
00377                                                 if( charJ < first_residue )
00378                                                         first_residue = charJ;
00379                                                 new_seq[ new_seq_charI ]= amino_acid_codes[ val ];
00380                                                 cur_seq_len++;
00381                                         }
00382                                         new_seq_charI++;
00383                                 }
00384                                 align_array.push_back( new_seq );
00385 //                              cerr << "new_seq.size() is: " << new_seq.size() << endl;
00386 #ifdef MISALIGNMENT_WORKAROUND
00387                                 cr.SetStart( seqI - 2, starts[ seqI - 2 ] );
00388                                 cr.SetLength( cur_seq_len, seqI - 2 );
00389 #else
00390                                 cr.SetStart( seqI - 1, starts[ seqI - 1 ] );
00391                                 cr.SetLength( cur_seq_len, seqI - 1 );
00392 #endif
00393                         }
00394                         int64 end_gap_count = align_array[ 0 ].size() - (last_residue - left_flank);
00395                         if( last_residue != -1 && end_gap_count > 0 ){
00396                                 for( seqI = 0; seqI < align_array.size(); seqI++ ){
00397                                         align_array[ seqI ] = align_array[ seqI ].substr( 0, align_array[ seqI ].size() - end_gap_count );
00398                                 }
00399                         }
00400                         int64 start_gap_count = left_flank + 1 - first_residue;
00401                         if( first_residue != align_length && start_gap_count > 0 ){
00402                                 for( seqI = 0; seqI < align_array.size(); seqI++ ){
00403                                         align_array[ seqI ] = align_array[ seqI ].substr( start_gap_count, align_array[ seqI ].size() - start_gap_count );
00404                                 }
00405                         }
00406                         cr.SetAlignment( align_array );
00407                 }
00408                 return true;
00409         }
00410 }catch(exception& e){
00411         cerr << "At: " << __FILE__ << ":" << __LINE__ << endl;
00412         cerr << e.what();
00413 }
00414         return false;
00415 }
00416 
00417 
00418 boolean ClustalInterface::CallClustal( vector< string >& seq_table ){
00419         char* phylip_name;
00420         
00421 //      if( allocated_aln )
00422                 free_aln( nseqs );
00423         alloc_aln( seq_table.size() );
00424         allocated_aln = true;
00425 
00426         if( distance_matrix.cols() == seq_table.size() ){
00427                 // copy tmat entries
00428                 for( uint seqI = 0; seqI < nseqs; seqI++ )
00429                         for( uint seqJ = 0; seqJ < nseqs; seqJ++ )
00430                                 tmat[ seqI + 1][ seqJ + 1 ] = 1 - distance_matrix( seqI, seqJ );
00431         }else{
00432                 // prepare to infer a phylo tree
00433                 phylip_name = (char * ) ckalloc( strlen( "tmp_tree.txt" ) + 1);
00434                 strcpy( phylip_name, "tmp_tree.txt" );
00435         }
00436 
00437         uint seqI;
00438         max_aln_length = 0;
00439         max_names = 0;
00440         for( seqI = 1; seqI <= seq_table.size(); seqI++ ){
00441                 seqlen_array[ seqI ] = seq_table[ seqI - 1 ].length();          /* store the length */
00442                 ostringstream ss;
00443                 ss << "seq" << seqI;
00444                 int namelen = ss.str().size();
00445                 names[ seqI ] = (char * ) ckalloc( namelen + 1 );
00446                 titles[ seqI ] = (char * ) ckalloc( namelen + 1 );
00447                 strcpy( names[ seqI ], ss.str().c_str());               /*    "   "  name   */
00448                 strcpy( titles[ seqI ], ss.str().c_str());              /*    "   "  title  */
00449 
00450                 // set max_names and max_aln_length
00451                 if( (int)strlen( names[ seqI ] ) > max_names )
00452                         max_names = strlen( names[ seqI ] );
00453                 if( seqlen_array[ seqI ] > max_aln_length )
00454                         max_aln_length = seqlen_array[ seqI ];
00455         }
00456 
00457         for( seqI = 1; seqI <= seq_table.size(); seqI++ ){
00458 
00459                 alloc_seq( seqI, max_aln_length );
00460                 char* seq_char_array = new char[ seq_table[ seqI - 1 ].length() + 2];
00461                 uint copyI = 0;
00462                 string& dna_seq = seq_table[ seqI - 1 ];
00463                 for( ; copyI < dna_seq.length(); copyI++ )
00464                         seq_char_array[ copyI + 1 ] = toupper( dna_seq[ copyI ] );
00465                 seq_char_array[ 0 ] = '-';      // silly clustal ignores the first character.
00466                 seq_char_array[ copyI + 1 ] = 0;
00467                 n_encode( seq_char_array, seq_array[ seqI ], dna_seq.length() );
00468                 delete[] seq_char_array;
00469         }
00470         max_aln_length *= 2;
00471 
00472 /*      struct_penalties1 = struct_penalties2 = NONE;
00473         if (sec_struct_mask1 != NULL) sec_struct_mask1=( char* )ckfree(sec_struct_mask1);
00474         if (sec_struct_mask2 != NULL) sec_struct_mask2=( char* )ckfree(sec_struct_mask2);
00475         if (gap_penalty_mask1 != NULL) gap_penalty_mask1=( char* )ckfree(gap_penalty_mask1);
00476         if (gap_penalty_mask2 != NULL) gap_penalty_mask2=( char* )ckfree(gap_penalty_mask2);
00477         if (ss_name1 != NULL) ss_name1=( char* )ckfree(ss_name1);
00478         if (ss_name2 != NULL) ss_name2=( char* )ckfree(ss_name2);
00479 */      
00480         nseqs = seq_table.size();
00481     gap_open   = dna_gap_open;
00482     gap_extend = dna_gap_extend;
00483     pw_go_penalty  = dna_pw_go_penalty;
00484     pw_ge_penalty  = dna_pw_ge_penalty;
00485 /*    ktup       = dna_ktup;
00486     window     = dna_window;
00487     signif     = dna_signif;
00488     wind_gap   = dna_wind_gap;
00489 */      dnaflag = TRUE;
00490         output_clustal = FALSE;
00491         
00492         int retval = 0;
00493         if( distance_matrix.cols() == seq_table.size() ){
00494 //              char* dump_file = "clustalout.txt";
00495 //              output_clustal = TRUE;
00496 //              if((clustal_outfile = open_explicit_file( dump_file ))==NULL) return false;
00497                 
00498                 retval = malign_nofiles( 0, false );
00499 //              create_alignment_output( 1, nseqs );
00500 //              fclose( clustal_outfile );      // this is done by the clustal output function
00501 
00502         }else{
00503                 pairalign((sint)0,nseqs,(sint)0,nseqs);
00504                 
00505                 FILE* tree;
00506                 if((tree = open_explicit_file( phylip_name ))==NULL) return false;
00507                 if (nseqs >= 2) {
00508                         guide_tree(tree,1,nseqs);
00509                 }
00510 
00511 //              char* dump_file = "clustalout.txt";
00512 //              if((clustal_outfile = open_explicit_file( dump_file ))==NULL) return false;
00513                 
00514                 retval = malign( 0, phylip_name );
00515 
00516                 phylip_name = (char*)ckfree( phylip_name );
00517         //      fclose( clustal_outfile );      // this is done by the clustal output function
00518         }
00519 
00520         if( retval <= 0 )
00521                 return false;
00522         return true;
00523 
00524 }
00525 
00526 /*
00527 lint get_aln_score(void)
00528 {
00529   static short  *mat_xref, *matptr;
00530   static sint maxres;
00531   static sint  s1,s2,c1,c2;
00532   static sint    ngaps;
00533   static sint    i,l1,l2;
00534   static lint    score;
00535   static sint   matrix[NUMRES][NUMRES];
00536 
00537 
00538   matptr = blosum45mt;
00539   mat_xref = def_aa_xref;
00540   maxres = get_matrix(matptr, mat_xref, matrix, TRUE, 100);
00541   if (maxres == 0)
00542     {
00543        fprintf(stdout,"Error: matrix blosum30 not found\n");
00544        return -1;
00545     }
00546 
00547   score=0;
00548   for (s1=1;s1<=nseqs;s1++)
00549    {
00550     for (s2=1;s2<s1;s2++)
00551       {
00552 
00553         l1 = seqlen_array[s1];
00554         l2 = seqlen_array[s2];
00555         for (i=1;i<l1 && i<l2;i++)
00556           {
00557             c1 = seq_array[s1][i];
00558             c2 = seq_array[s2][i];
00559             if ((c1>=0) && (c1<=max_aa) && (c2>=0) && (c2<=max_aa))
00560                 score += matrix[c1][c2];
00561           }
00562 
00563         ngaps = count_gaps(s1, s2, l1);
00564 
00565         score -= (int)(100 * gap_open * ngaps);
00566 
00567       }
00568    }
00569 
00570   score /= 100;
00571 
00572   return score;
00573 }
00574 */
00575 
00576 }

Generated on Fri Mar 14 06:01:02 2008 for libMems by doxygen 1.3.6