Main Page   Modules   Class Hierarchy   Compound List   File List   Compound Members  

Quantity.C

00001 #include <citrus/config.h>
00002 
00003 #include <stdio.h>
00004 #include <math.h>
00005 
00006 #include <glib.h>
00007 
00008 #include <stdexcept>
00009 
00010 #include <citrus/Dimension.H>
00011 #include <citrus/DimensionGroup.H>
00012 #include <citrus/UnitExpr.H>
00013 #include <citrus/Prefix.H>
00014 #include <citrus/Unit.H>
00015 
00016 // Shamelessly horked from poly.lex.C
00017 #define yy_create_buffer up_create_buffer
00018 #define yy_delete_buffer up_delete_buffer
00019 #define yy_scan_buffer up_scan_buffer
00020 #define yy_scan_string up_scan_string
00021 #define yy_scan_bytes up_scan_bytes
00022 #define yy_flex_debug up_flex_debug
00023 #define yy_init_buffer up_init_buffer
00024 #define yy_flush_buffer up_flush_buffer
00025 #define yy_load_buffer_state up_load_buffer_state
00026 #define yy_switch_to_buffer up_switch_to_buffer
00027 #define yyin upin
00028 #define yyleng upleng
00029 #define yylex uplex
00030 #define yyout upout
00031 #define yyrestart uprestart
00032 #define yytext uptext
00033 #define yywrap upwrap
00034 
00035 #include <citrus/lex.H>
00036 #include "upParser.hh"
00037 #include <citrus/Quantity.H>
00038 
00039 extern FILE* upin ;
00040 extern FILE* upout ;
00041 extern int upparse() ;
00042 extern YYSTYPE uplval ;
00043 extern Quantity* theResult ;
00044 
00045 /* Debugging flags.
00046  * Define a flag. Pull my finger.
00047  *
00048  * DBG_CONVERT          Print the units and dimensions of the quantities
00049  *                      to be converted.
00050  */
00051 
00076 void Quantity::eval( UnitExpr*                  e,
00077                      vector<UnitPower>&         upwr,
00078                      vector<DimensionPower>&    dpwr,
00079                      double&                    s )
00080 {
00081   p_eval( e, 1, upwr, dpwr, s ) ;
00082   /* Now, strip out any units/dimensions that have a 0 exponent */
00083   
00084 }
00085 
00091 void Quantity::p_eval( UnitExpr*                e,
00092                        int                      x,
00093                        vector<UnitPower>&       upwr,
00094                        vector<DimensionPower>&  dpwr,
00095                        double&                  s )
00096 {
00097   UnitUnitInfo*                         ui ;
00098   UnitOperInfo*                         oi ;
00099   DimensionGroup*                       dgrp ;
00100   DimensionPower                        dp ;
00101   vector<DimensionPower>::iterator      dm ;
00102   vector<UnitPower>::iterator           un ;
00103 
00104   switch (e->m_i->type()) {
00105   case UnitInfo::UNIT:
00106     ui = (UnitUnitInfo*)e->m_i ;
00107     // Only change if operand has dimension to impart
00108     if ( ui->m_u ) {
00109       double dscale = 1.0 ;
00110       if ( ui->m_p )
00111         dscale *= pow(10, ui->m_p->exp() ) ;
00112       dscale *=  ui->m_u->scale() ;
00113       s *= pow( dscale , x*ui->exp() ) ;
00114       // Don't ever put the "none" dimension into a product!
00115       if ( ui->m_u != Unit::dimensionless() ) {
00116         un = find_unit( ui->m_u, upwr ) ;
00117         if ( un != upwr.end() ) {
00118           un->m_pwr += ui->exp()*x ;
00119           if ( un->m_pwr == 0 )
00120             upwr.erase( un ) ;
00121         } else {
00122           upwr.push_back( UnitPower( ui->m_u, ui->m_p, ui->exp()*x ) ) ;
00123         }
00124         dgrp = ui->m_u->dgrp() ;
00125         vector<DimensionPower>::iterator iter = dgrp->m_dims.begin() ;
00126         while ( iter != dgrp->m_dims.end() ) {
00127           dp = *iter ;
00128           dm=find_dimn(dp.m_dim,dpwr) ;
00129           if ( dm != dpwr.end() ) {
00130             dm->m_pwr += dp.m_pwr*ui->exp()*x ;
00131             if ( dm->m_pwr == 0 )
00132               dpwr.erase( dm ) ;
00133           } else {
00134             dpwr.push_back( DimensionPower(dp.m_dim, dp.m_pwr*ui->exp()*x));
00135           }
00136           ++iter ;
00137         }
00138       }
00139     }
00140     break ;
00141   case UnitInfo::OPER:
00142     oi = (UnitOperInfo*)e->m_i ;
00143     if (e->left())
00144       p_eval( e->left(), x, upwr, dpwr, s ) ;
00145     if (e->right())
00146       p_eval( e->right(), oi->op()=='/' ? -1*x : x, upwr, dpwr, s ) ;
00147     break ;
00148   }
00149   return ;
00150 }
00151 
00157 Quantity::Quantity()
00158 {
00159   m_val = dtNaN ;
00160   m_dimn.push_back( DimensionPower( find_dsym('1'), 1 ) ) ;
00161   m_units.push_back( UnitPower( Unit::dimensionless(), 0, 1 ) ) ;
00162   m_dgrp = Unit::dimensionless()->dgrp() ;
00163   m_scale = 1.0 ;
00164 }
00165 
00168 Quantity::Quantity( const Quantity& qty )
00169 {
00170   m_val = qty.m_val ;
00171   m_dimn = qty.m_dimn ;
00172   m_units = qty.m_units ;
00173   m_dgrp = qty.m_dgrp ;
00174   m_scale = qty.m_scale ;
00175 }
00176 
00182 Quantity::Quantity( const char* dimNum )
00183 {
00184   if (theResult)
00185     delete theResult ;
00186 
00187   //fprintf( stderr, "Parsing :%s:\n", dimNum ) ;
00188   int   tlen = strlen(dimNum) ;
00189   char* tmp = new char[tlen+2] ;
00190   strcpy( tmp, dimNum ) ;
00191   sprintf(tmp+tlen,"\n") ;
00192   YY_BUFFER_STATE bstate = up_scan_string( tmp ) ;
00193 
00194   bool parsed = !upparse() ;
00195 
00196   up_delete_buffer( bstate ) ;
00197   delete [] tmp ;
00198 
00199   if ( parsed && theResult ) {
00200     m_val = theResult->m_val ;
00201     m_dimn = theResult->m_dimn ;
00202     m_units = theResult->m_units ;
00203     m_dgrp = theResult->m_dgrp ;
00204     m_scale = theResult->m_scale ;
00205   } else {
00206     throw new runtime_error( "Could not parse units" ) ;
00207   }
00208 }
00209 
00212 Quantity::Quantity( double v, UnitExpr* e )
00213   : m_val(v)
00214 {
00215   m_scale = 1.0 ;
00216   p_eval( e, 1, m_units, m_dimn, m_scale ) ;
00217   if ( m_units.size() == 0 )
00218     m_units.push_back( UnitPower( Unit::dimensionless(), 0, 1 ) ) ;
00219   if ( m_dimn.size() == 0 ) 
00220     m_dimn.push_back( DimensionPower( find_dsym('1'), 1 ) ) ;
00221   m_dgrp = DimensionGroup::find( m_dimn );
00222 }
00223 
00226 Quantity::~Quantity()
00227 {
00228 
00229 }
00230 
00233 void Quantity::print()
00234 {
00235   fprintf( stdout, " %f [", m_val ) ;
00236   UnitPower::print( m_units, stdout ) ;
00237   fprintf( stdout, "] {" ) ;
00238   //DimensionPower::print( m_dimn ) ;
00239   fprintf( stdout, "}\n" ) ;
00240 }
00241 
00249 bool Quantity::operator == ( const Quantity& o ) const
00250 {
00251   if ( m_val != o.m_val )
00252     return false ;
00253 
00254   if ( m_dgrp && o.m_dgrp && m_dgrp == o.m_dgrp )
00255     return true ;
00256 
00257   return ( m_dimn == o.m_dimn ) ;
00258 }
00259 
00275 int convert( Quantity* to, const Quantity* from )
00276 {
00277 #ifdef DBG_CONVERT
00278   fprintf( stderr, "Convert [") ;
00279   UnitPower::print( from->m_units, stderr ) ;
00280   fprintf( stderr, "] {" ) ;
00281   DimensionPower::print( from->m_dimn, stderr ) ;
00282   fprintf( stderr, "} to [" ) ;
00283   UnitPower::print( to->m_units, stderr ) ;
00284   fprintf( stderr, "] {" ) ;
00285   DimensionPower::print( to->m_dimn, stderr ) ;
00286   fprintf( stderr, "}\n" ) ;
00287 #endif // DBG_CONVERT
00288 
00289   if ( (from && to ) &&
00290        areDimensionsMatched(from->dimension(), to->dimension()) ) {
00291 
00292     if ( from->m_units.size() == 1 && 
00293          to->m_units.size() == 1 && 
00294          (from->m_units[0].m_unit->offsetPolicy() ||
00295           to->m_units[0].m_unit->offsetPolicy()) ) {
00296 
00297       // offsets only make sense if we haven't multiplied units.
00298       double o_from = from->m_units[0].m_unit->offsetValue()  ;
00299       double o_to = to->m_units[0].m_unit->offsetValue() ;
00300       to->m_val = ( from->val() + o_from ) * from->scale()/to->scale() - o_to ;
00301     } else {
00302       to->m_val = from->val() * from->scale()/to->scale() ;
00303     }
00304     return 0 ;
00305   } 
00306   to->m_val = dtNaN ;
00307   return 1 ;
00308 }
00309 
00313 xmlNodePtr Quantity::mathML() const
00314 {
00315   CHAR* content ;
00316   xmlNodePtr top = xmlNewNode( NULL, (const CHAR*)"mrow" ) ;
00317 
00318   content = (CHAR*) g_strdup_printf( "%g", m_val ) ;
00319   xmlNewChild( xmlNewChild( top, NULL, (const CHAR*)"mrow", NULL ),
00320                NULL, (const CHAR*)"mi", content ) ;
00321   g_free( content ) ;
00322 
00323   xmlNewChild( top, NULL,
00324                (const CHAR*)"mo", (const CHAR*)"&NonBreakingSpace;" ) ;
00325   xmlAddChild( top, UnitPower::mathML( m_units ) ) ;
00326 
00327   return top ;
00328 }
00329 
Citrus C++ Reference Manual  20010520