/***************************************************************************
unit.h - Header file for class unit, an extension class to GiNaC
-------------------
begin : Mon Oct 22 2001
copyright : (C) 2001 by Jan Rheinlaender
email : jrheinlaender@users.sourceforge.net
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef UNIT_H
#define UNIT_H
/**
* @author Jan Rheinlaender
* @short Extends GiNaC to handle physical units, i.g., "x = 1 mm", "1 m + 1 mm = 1,001 m"
*/
#include "utils.h"
#include <string>
#include <stdexcept>
#include <ginac/ginac.h>
using namespace GiNaC;
#include "expression.h" // *** added in 0.4
/// Helper class to initialize class Unit *** added in 0.5
class unit_init {
public:
unit_init();
~unit_init();
private:
/// A boolean used to ensure that init() is only called once in the lifetime of the class
static bool called;
static unit_init unit_initializer;
};
/**
* Internal GiNaC identifier for class Unit
*/
//const unsigned TINFO_Unit = 0x42420001U; *** removed in 1.2.1
/// Extends GiNaC to handle physical units
class Unit : public basic {
GINAC_DECLARE_REGISTERED_CLASS(Unit, basic)
public:
friend class unit_init;
/**
* Construct a Unit with the given name.
* @param n A string with the name of the unit
*/
Unit(const std::string &n);
/**
* Print the unit in a GiNaC print context.
* @param c The print context (e.g., print_latex)
* @param level Unused, for consistency with GiNaC print methods
*/
// *** changed name to do_print in 0.8
void do_print(const print_context &c, unsigned level = 0) const;
/**
* Return the name of the unit
* @returns A string with the name of the unit
*/
inline const std::string get_name() const { return(name); }
/// Set the print name of the unit
inline void set_printname(const std::string& pn) { printname = pn; }
/// Get the print name of the unit
inline const std::string get_printname() const { return printname; } // *** changed in 1.4.1
/**
* Required by GiNac, does nothing. It would be possible to define simplification or
* canonicalization rules here
* @param level Unused, required by GiNaC
* @returns An expression with the result of the evaluation
*/
ex eval(int level = 0) const;
/// archive the unit
void archive(archive_node& n) const; // *** added in 1.3.1
/// unarchive the unit
void read_archive(const archive_node& n, lst& syms); // *** added in 1.3.1
// static (class) functions
/// Return the Unit for the given Unit name. This Unit is unique and the same Unit is returned every time
static Unit get(const std::string &n); // *** added in 1.4.1
static Unit* getp(const std::string &n);
/**
* Looks the unit given by its name up in the conversion table, and returns an equivalent expression of
* base units.
* Issues an error if there is no entry for this unit name in the conversion table, and returns a (base)
* unit with the name "unknown".
* @param unit A string with the name of the unit that is to be looked up
* @returns An expression with the units corresponding to the name given
*/
static expression canonicalize_from(const std::string &unit); // *** changed ex to expression in 0.4
/**
* Takes an expression and turns all units in it to base units. The expression must be a unit or a mul of
* units and their powers. Any numerics found are left untouched. Symbols are accepted as well, to
* allow for constants like \\pi. If any other GiNaC types are found in the expression, the method issues
* a warning and leaves them untouched.
* @param units The expression that is to be canonicalized
* @returns An expression containing only base units, numerics and symbols
*/
static expression canonicalize(const expression &units); // *** changed ex to expression in 0.4
/**
* Adds a unit name to the list of unit names.
* @param uname The name of the unit
*/
static void add_unitname(const std::string &uname);
/**
* Add a new unit conversion rule to the class. The unit with the name "uname" can be expressed
* by the expression "other_units". This method issues a warning if a conversion with this name
* already exists, and overwrites it with the new one.
* @param uname The unit name for which the conversion is to be added
* @param other_units An expression with the units which are equivalent to "uname"
*/
static void add_conversion(const std::string &uname, const expression &other_units);
/** // *** added in 0.3, changed back to use lst in 0.9, changed back to vector in 1.0, made public in 1.2
* Create the conversion list from a list of preferred units
* @param units A vector of the preferred units
* @returns A vector of the necessary conversions
*/
// Note: The method returns a pointer for efficiency reasons
static std::vector<relational> *create_conversions(const std::vector<expression> &units);
/// Set option to a list value
// *** replaces set_preferred_units in 1.1
// *** moved to eqc.cpp/optstack.cpp in 1.2
/**
* Returns true if the unit name was previously registered using add_unitname, or is a base unit
* @param uname The unit name
* @returns True if the unit name is find in the list of unit names
*/
static bool is_unitname(const std::string &uname);
/** // *** renamed and added parameter l in 0.3
* Substitutes all units in the expression with the users preferred units.
* If this function does not give the
* desired result, check whether the preferred units should be registered in a different order!
* @param e The expression in which the units are to be substituted
* @returns An expression with the result of the substitution
*/
static expression subst_units(const expression &e);
/**
* Return the unit conversion table and the list of known unit names to the state after init()
*/
static void clear();
/// Print class information onto a stream
static void print(std::ostream &os);
/// Print class information onto a message stream
//static void print(message &ms); // *** added in 0.7, changed in 1.3.1
private:
/// The name of the unit
std::string name;
/// The name to be used for printing
std::string printname; // *** added in 1.3.1 for iMath
// *** added in 1.4.1
/// A map of the unitnames -> Units to consistently return the same object for a unitname
static std::map<std::string, Unit*> factory;
/// A map with the unit conversions
static std::map<std::string, expression> conversions; // *** changed ex to expression in 0.4
/// A set containing the names of the base units
static std::set<const char*, ltstr> base_units;
/// A set of unit names that could be encountered by latex parsing
static std::set<const char*, ltstr> unitnames;
static bool initialized; // *** added in 1.3.1
public:
/**
* Initialize the unit conversion table and the list of known unit names with the SI base units
*/
static void init(); // *** made public in 1.3.1
// *** moved here in 1.3.1
static Unit* metre;
static Unit* kilogram;
static Unit* second;
static Unit* ampere;
static Unit* kelvin;
static Unit* celsius;
static Unit* mole;
static Unit* candela;
};
GINAC_DECLARE_UNARCHIVER(Unit);
#endif