source: trunk/include/core/RpUnits.h @ 116

Last change on this file since 116 was 116, checked in by dkearney, 19 years ago
  1. rewrote RpUnits::define(...) and RpUnits::convert(...) fxns.
  2. added functionality so you no longer need to call add_presets(...)
  3. RpUnits can now handle conversions as follows 1cm2/Vs -> 1e-7m2/kVus
  4. Cannot handle conversions dealing with Temperature very well because

Temperature conversions have offsets (+/- 32...). you can still do
F->C and Fs->Cs, but Fms->Cs provides unreliable results. (not to
mention that i'm still unsure how to do a conversion like this.

  1. still need to add Fo (delta fahrenheit) and Co (delta celcius)

units and conversions. These should not be effected by the notorious
temperature

  1. adjusted RpUnits_test.cc for testing. python.fortran and matlab

bindings have not been tested yet.

  • Property svn:executable set to *
File size: 18.1 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  RpUnits.h - Header file for Rappture Units
4 *
5 *   RpUnits Class Declaration / Definition
6 *
7 * ======================================================================
8 *  AUTHOR:  Derrick Kearney, Purdue University
9 *  Copyright (c) 2004-2005  Purdue Research Foundation
10 *
11 *  See the file "license.terms" for information on usage and
12 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 * ======================================================================
14 */
15#include <iostream>
16#include <string>
17#include <list>
18#include <sstream>
19#include <stdlib.h>
20#include <errno.h>
21#include <math.h>
22
23#include "RpDict.h"
24#include "RpUnitsStd.h"
25
26#ifndef _RpUNITS_H
27#define _RpUNITS_H
28
29#define LIST_TEMPLATE RpUnitsListEntry
30
31// should the define function:
32// 1. compare portions of inStr to unit names that have previously
33//    been defined (you must parse in order for this option to work)
34#define COMPARE_MASK    1
35// 2. create a unit if no unit by the name exists.
36#define CREATE_MASK     2
37// 3. parse the unit name to try to find previously defined units.
38#define PARSE_MASK      4
39
40class RpUnits;
41
42class RpUnitsPreset {
43    public:
44        RpUnitsPreset () {
45            addPresetAll();
46        };
47
48        static int addPresetAll();
49        static int addPresetEnergy();
50        static int addPresetLength();
51        static int addPresetTemp();
52        static int addPresetTime();
53        static int addPresetVolume();
54};
55
56// simple class to hold info about a conversion.
57// holds where we are converting from
58// holds where we are converting to
59// hold the pointer to a function to do the forward conversion (from->to)
60// hold the pointer to a function to do the backward conversion (to->from)
61//
62class conversion
63{
64    public:
65
66        const RpUnits* getFrom()    { return (const RpUnits*) fromPtr; };
67        const RpUnits* getTo()      { return (const RpUnits*) toPtr; };
68
69        friend class RpUnits;
70
71        // copy constructor
72        conversion ( conversion& other)
73            :   fromPtr             (other.fromPtr),
74                toPtr               (other.toPtr),
75                convForwFxnPtr      (other.convForwFxnPtr),
76                convBackFxnPtr      (other.convBackFxnPtr),
77                convForwFxnPtrDD    (other.convForwFxnPtrDD),
78                convBackFxnPtrDD    (other.convBackFxnPtrDD),
79                convForwFxnPtrVoid  (other.convForwFxnPtrVoid),
80                convForwData        (other.convForwData),
81                convBackFxnPtrVoid  (other.convBackFxnPtrVoid),
82                convBackData        (other.convBackData)
83            {};
84
85        // copy assignment operator
86        conversion& operator= ( conversion& other )
87            {
88                fromPtr             = other.fromPtr;
89                toPtr               = other.toPtr;
90                convForwFxnPtr      = other.convForwFxnPtr;
91                convBackFxnPtr      = other.convBackFxnPtr;
92                convForwFxnPtrDD    = other.convForwFxnPtrDD;
93                convBackFxnPtrDD    = other.convBackFxnPtrDD;
94                convForwFxnPtrVoid  = other.convForwFxnPtrVoid;
95                convForwData        = other.convForwData;
96                convBackFxnPtrVoid  = other.convBackFxnPtrVoid;
97                convBackData        = other.convBackData;
98                return *this;
99            }
100
101        // default destructor
102        virtual ~conversion ()
103        {}
104
105    private:
106
107        const RpUnits* fromPtr;
108        const RpUnits* toPtr;
109        double (*convForwFxnPtr)(double);
110        double (*convBackFxnPtr)(double);
111        double (*convForwFxnPtrDD)(double,double);
112        double (*convBackFxnPtrDD)(double,double);
113        void* (*convForwFxnPtrVoid)(void*, void*);
114        void* convForwData;
115        void* (*convBackFxnPtrVoid)(void*, void*);
116        void* convBackData;
117
118        // constructor
119        // private because i only want RpUnits to be able to
120        // create a conversion
121        conversion (
122                const RpUnits* fromPtr,
123                const RpUnits* toPtr,
124                double (*convForwFxnPtr)(double),
125                double (*convBackFxnPtr)(double)
126             )
127            :   fromPtr             (fromPtr),
128                toPtr               (toPtr),
129                convForwFxnPtr      (convForwFxnPtr),
130                convBackFxnPtr      (convBackFxnPtr),
131                convForwFxnPtrDD    (NULL),
132                convBackFxnPtrDD    (NULL),
133                convForwFxnPtrVoid  (NULL),
134                convForwData        (NULL),
135                convBackFxnPtrVoid  (NULL),
136                convBackData        (NULL)
137            {};
138
139        // constructor for 2 argument conversion functions
140        conversion (
141                const RpUnits* fromPtr,
142                const RpUnits* toPtr,
143                double (*convForwFxnPtr)(double,double),
144                double (*convBackFxnPtr)(double,double)
145             )
146            :   fromPtr             (fromPtr),
147                toPtr               (toPtr),
148                convForwFxnPtr      (NULL),
149                convBackFxnPtr      (NULL),
150                convForwFxnPtrDD    (convForwFxnPtr),
151                convBackFxnPtrDD    (convBackFxnPtr),
152                convForwFxnPtrVoid  (NULL),
153                convForwData        (NULL),
154                convBackFxnPtrVoid  (NULL),
155                convBackData        (NULL)
156            {};
157
158        // constructor for user defined void* returning 1 arg conversion fxns.
159        // the 1 arg is a user defined void* object
160        conversion (
161                const RpUnits* fromPtr,
162                const RpUnits* toPtr,
163                void* (*convForwFxnPtrVoid)(void*, void*),
164                void* convForwData,
165                void* (*convBackFxnPtrVoid)(void*, void*),
166                void* convBackData
167             )
168            :   fromPtr             (fromPtr),
169                toPtr               (toPtr),
170                convForwFxnPtr      (NULL),
171                convBackFxnPtr      (NULL),
172                convForwFxnPtrDD    (NULL),
173                convBackFxnPtrDD    (NULL),
174                convForwFxnPtrVoid  (convForwFxnPtrVoid),
175                convForwData        (convForwData),
176                convBackFxnPtrVoid  (convBackFxnPtrVoid),
177                convBackData        (convBackData)
178            {};
179
180};
181
182// used by the RpUnits class to create a linked list of the conversions
183// associated with the specific unit.
184//
185// we could templitize this and make a generic linked list
186// or could use generic linked list class from book programming with objects
187//
188class convEntry
189{
190
191    public:
192
193        friend class RpUnits;
194
195        virtual ~convEntry()
196        {}
197
198    private:
199
200        conversion* conv;
201        convEntry*  prev;
202        convEntry*  next;
203
204        convEntry (
205                conversion* conv,
206                convEntry*  prev,
207                convEntry*  next
208             )
209            :   conv    (conv),
210                prev    (prev),
211                next    (next)
212            {};
213
214};
215
216class RpUnitsListEntry
217{
218
219    public:
220
221        // constructor
222        RpUnitsListEntry (const RpUnits* unit, double exponent)
223            : unit     (unit),
224              exponent (exponent)
225        {};
226
227        // copy constructor
228        RpUnitsListEntry (const RpUnitsListEntry& other)
229            : unit     (other.unit),
230              exponent (other.exponent)
231        {};
232
233        // copy assignment operator
234        RpUnitsListEntry& operator= (const RpUnitsListEntry& other) {
235            unit = other.unit;
236            exponent = other.exponent;
237            return *this;
238        }
239
240        // negate the exponent
241        void negateExponent() const;
242
243        // print the name of the object
244        std::string name() const;
245
246        // report the basis of the RpUnits object being stored.
247        const RpUnits* getBasis() const;
248
249        // return the RpUnits*
250        const RpUnits* getUnitsObj() const;
251
252        // return the exponent
253        double getExponent() const;
254
255        // destructor
256        virtual ~RpUnitsListEntry ()
257        {}
258
259    private:
260
261        const RpUnits* unit;
262        mutable double exponent;
263};
264
265class RpUnits
266{
267    /*
268     * helpful units site
269     * http://aurora.regenstrief.org/~gunther/units.html
270     * http://www.nodc.noaa.gov/dsdt/ucg/
271     * http://www.cellml.org/meeting_minutes/archive/
272     *        20010110_meeting_minutes.html
273     */
274
275    public:
276
277        // users member fxns
278        std::string getUnits() const;
279        std::string getUnitsName() const;
280        double getExponent() const;
281        const RpUnits* getBasis() const;
282
283        // convert from one RpUnits to another if the conversion is defined
284        double convert(         const RpUnits* toUnits,
285                                double val,
286                                int* result=NULL    ) const;
287        // convert from one RpUnits to another if the conversion is defined
288        void* convert(          const RpUnits* toUnits,
289                                void* val,
290                                int* result=NULL) const;
291        // convert from one RpUnits to another if the conversion is defined
292        // double convert(std::string, double val);
293        // convert from one RpUnits to another if the conversion is defined
294        std::string convert (   const RpUnits* toUnits,
295                                double val,
296                                int showUnits = 0,
297                                int* result = NULL  ) const;
298
299        static std::string convert ( std::string val,
300                                     std::string toUnits,
301                                     int showUnits,
302                                     int* result = NULL );
303
304        /*
305        static std::string convert ( std::string val,
306                                     std::string toUnits,
307                                     int showUnits,
308                                     int* result = NULL );
309        */
310
311        // dictionary to store the units.
312        // static RpDict<std::string,RpUnits> dict;
313
314        // turn the current unit to the metric system
315        // this should only be used for units that are part of the
316        // metric system. doesnt deal with exponents, just prefixes
317        double makeBasis(double value, int* result = NULL) const;
318        const RpUnits & makeBasis(double* value, int* result = NULL) const;
319
320        static int makeMetric(const RpUnits * basis);
321
322        // find a RpUnits object that should exist in RpUnitsTable
323        // returns 0 on success (object was found)
324        // returns !0 on failure (object not found)
325        static const RpUnits* find(std::string key);
326
327        // user calls define to add a RpUnits object or to add a relation rule
328        //
329        // add RpUnits Object
330        static RpUnits * define(const std::string units,
331                                const RpUnits* basis=NULL   );
332        // static RpUnits * defineCmplx(   const std::string units,
333        //                                 const RpUnits* basis);
334        //
335        // add relation rule
336
337        static RpUnits * define(const RpUnits* from,
338                                const RpUnits* to,
339                                double (*convForwFxnPtr)(double),
340                                double (*convBackFxnPtr)(double));
341
342        static RpUnits * define(const RpUnits* from,
343                                const RpUnits* to,
344                                double (*convForwFxnPtr)(double,double),
345                                double (*convBackFxnPtr)(double,double));
346
347        static RpUnits * define(const RpUnits* from,
348                                const RpUnits* to,
349                                void* (*convForwFxnPtr)(void*, void*),
350                                void* convForwData,
351                                void* (*convBackFxnPtr)(void*, void*),
352                                void* convBackData);
353
354        // populate the dictionary with a set of units specified by group
355        // if group equals......................then load................
356        //      "all"                       load all available units
357        //      "energy"                    load units related to energy
358        //      "length"                    load units related to length
359        //      "temp"                      load units related to temperature
360        //      "time"                      load units related to time
361        //      "volume"                    load units related to volume
362        //  (no other groups have been created)
363
364        static int addPresets (const std::string group);
365
366        // undefining a relation rule is probably not needed
367        // int undefine(); // delete a relation
368
369        // why are these functions friends...
370        // probably need to find a better way to let RpUnits
371        // use the RpDict and RpDictEntry fxns
372        friend class RpDict<std::string,RpUnits*>;
373        friend class RpDictEntry<std::string,RpUnits*>;
374
375        friend int insert(std::string key,RpUnits* val);
376
377
378        // copy constructor
379        RpUnits (RpUnits &other)
380            : units    (other.units),
381              exponent (other.exponent),
382              basis    (other.basis),
383              convList (NULL)
384        {
385            convEntry* q = NULL;
386            convEntry* curr = NULL;
387
388            dict = other.dict;
389
390            if (other.convList) {
391                q = other.convList;
392                convList = new convEntry (q->conv,NULL,NULL);
393                curr = convList;
394                while (q->next) {
395                    q = q->next;
396                    curr->next = new convEntry (q->conv,curr,NULL);
397                    curr = curr->next;
398                }
399            }
400        }
401
402        // copy assignment operator
403        RpUnits& operator= (const RpUnits& other) {
404
405            convEntry* q = NULL;
406            convEntry* curr = NULL;
407
408            if ( this != &other ) {
409                delete convList;
410            }
411
412            dict = other.dict;
413            units = other.units;
414            exponent = other.exponent;
415            basis = other.basis;
416
417            if (other.convList) {
418                q = other.convList;
419                convList = new convEntry (q->conv,NULL,NULL);
420                curr = convList;
421                while (q->next) {
422                    q = q->next;
423                    curr->next = new convEntry (q->conv,curr,NULL);
424                    curr = curr->next;
425                }
426            }
427
428            return *this;
429        }
430
431        // default destructor
432        //
433        ~RpUnits ()
434        {
435            // clean up dynamic memory
436
437            convEntry* p = convList;
438            convEntry* tmp = p;
439
440            while (p != NULL) {
441                tmp = p;
442                p = p->next;
443                delete tmp;
444            }
445        }
446
447    private:
448
449        // i hope to replace these vars with a small class representing a
450        // of a linked list of units. that way we can handle complex units.
451        // this will also require that we move the getUnits, getExponent,
452        // and getBasis, makeBasis functionality into the smaller class,
453        // that represents each part of the units. we should keep getUnits,
454        // getBasis, and makeBasis in this class, but modify them to go
455        // through the linked list of units and combine the units back into
456        // what the caller expects to see.
457        // ie. cm2/Vms (mobility), will be split into the objects cm2, V, ms
458        // when getUnits is called, the user should see cm2/Vms again.
459        // for basis, possibly let the user choose a basis, and for makeBasis
460        // move through the linked list, only converting the metric elements.
461        //
462
463        std::string units;
464        double exponent;
465        const RpUnits* basis;
466
467        // linked list of units this RpUnit can convert to
468        // its mutable because the connectConversion function takes in a
469        // const RpUnits* and attempts to change the convList variable
470        // within the RpUnits Object
471        mutable convEntry* convList;
472
473
474        // dictionary to store the units.
475        static RpDict<std::string,RpUnits*>* dict;
476
477        // create a units element
478        // class takes in three pieces of info
479        // 1) string describing the units
480        // 2) double describing the exponent
481        // 3) pointer to RpUnits object describing the basis
482        //      of the units (the fundamental unit)
483        //
484
485        RpUnits (
486                    const std::string& units,
487                    double& exponent,
488                    const RpUnits* basis
489                )
490            :   units       (units),
491                exponent    (exponent),
492                basis       (basis),
493                convList    (NULL)
494        {};
495
496        // insert new RpUnits object into RpUnitsTable
497        // returns 0 on success (object inserted or already exists)
498        // returns !0 on failure (object cannot be inserted or dne)
499        // int RpUnits::insert(std::string key) const;
500
501        typedef std::list<LIST_TEMPLATE> RpUnitsList;
502        typedef RpUnitsList::iterator RpUnitsListIter;
503
504        void newExponent(double newExponent) {exponent = newExponent;};
505
506        static int units2list( const std::string& inUnits,
507                               RpUnitsList& outList         );
508        static int grabExponent(const std::string& inStr, double* exp);
509        static int grabUnitString( const std::string& inStr);
510        static const RpUnits* grabUnits (std::string inStr, int* offset);
511        static int negateListExponents(RpUnitsList& unitsList);
512        static int RpUnits::printList(RpUnitsList& unitsList);
513
514        static int RpUnits::compareListEntryBasis( RpUnitsList& fromList,
515                                                   RpUnitsListIter& fromIter,
516                                                   RpUnitsListIter& toIter);
517
518        static int RpUnits::compareListEntrySearch( RpUnitsList& fromList,
519                                                    RpUnitsListIter& fromIter,
520                                                    RpUnitsListIter& toIter);
521
522        void RpUnits::connectConversion(conversion* conv) const;
523
524};
525
526/*--------------------------------------------------------------------------*/
527/*--------------------------------------------------------------------------*/
528
529#endif
Note: See TracBrowser for help on using the repository browser.