URI: 
       tUnits.cc - pism - [fork] customized build of PISM, the parallel ice sheet model (tillflux branch)
  HTML git clone git://src.adamsgaard.dk/pism
   DIR Log
   DIR Files
   DIR Refs
   DIR LICENSE
       ---
       tUnits.cc (4823B)
       ---
            1 /* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018 PISM Authors
            2  *
            3  * This file is part of PISM.
            4  *
            5  * PISM is free software; you can redistribute it and/or modify it under the
            6  * terms of the GNU General Public License as published by the Free Software
            7  * Foundation; either version 2 of the License, or (at your option) any later
            8  * version.
            9  *
           10  * PISM is distributed in the hope that it will be useful, but WITHOUT ANY
           11  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
           12  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
           13  * details.
           14  *
           15  * You should have received a copy of the GNU General Public License
           16  * along with PISM; if not, write to the Free Software
           17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
           18  */
           19 
           20 #include "Units.hh"
           21 
           22 #include "pism/util/error_handling.hh"
           23 
           24 #include "pism_utilities.hh"
           25 
           26 namespace pism {
           27 
           28 namespace units {
           29 
           30 class ut_system_deleter {
           31 public:
           32   void operator()(ut_system* p) const {
           33     ut_free_system(p);
           34   }
           35 };
           36 
           37 /** Initialize the unit system by reading from an XML unit
           38  * definition file.
           39  */
           40 System::System(const std::string &path) {
           41   ut_system *tmp;
           42 
           43   ut_set_error_message_handler(ut_ignore);
           44 
           45   if (not path.empty()) {
           46     tmp = ut_read_xml(path.c_str());
           47   } else {
           48     tmp = ut_read_xml(NULL);
           49   }
           50 
           51   if (tmp == NULL) {
           52     throw RuntimeError::formatted(PISM_ERROR_LOCATION, "ut_read_xml(%s) failed", path.c_str());
           53   }
           54   ut_set_error_message_handler(ut_write_to_stderr);
           55 
           56   m_system = std::shared_ptr<ut_system>(tmp, ut_system_deleter());
           57 }
           58 
           59 //! \brief Convert a quantity from unit1 to unit2.
           60 /*!
           61  * Example: convert(1, "m year-1", "m second-1").
           62  *
           63  * Please avoid using in computationally-intensive code.
           64  */
           65 double convert(System::Ptr system, double input,
           66                const std::string &spec1, const std::string &spec2) {
           67   Converter c(Unit(system, spec1), Unit(system, spec2));
           68 
           69   return c(input);
           70 }
           71 
           72 Unit::Unit(System::Ptr system, const std::string &spec)
           73   : m_unit(NULL), m_system(system) {
           74   m_unit = ut_parse(m_system->m_system.get(), spec.c_str(), UT_ASCII);
           75   if (m_unit == NULL) {
           76     throw RuntimeError::formatted(PISM_ERROR_LOCATION, "unit specification '%s' is unknown or invalid",
           77                                   spec.c_str());
           78   }
           79   m_unit_string = spec;
           80 }
           81 
           82 Unit::Unit(const Unit &other)
           83   : m_system(other.m_system) {
           84 
           85   m_unit = ut_clone(other.m_unit);
           86   if (m_unit == NULL) {
           87     throw RuntimeError(PISM_ERROR_LOCATION, "ut_clone failed");
           88   }
           89 
           90   m_system      = other.m_system;
           91   m_unit_string = other.m_unit_string;
           92 }
           93 
           94 Unit& Unit::operator=(const Unit& other) {
           95   if (this == &other) {
           96     return *this;
           97   }
           98 
           99   reset();
          100 
          101   m_system      = other.m_system;
          102   m_unit_string = other.m_unit_string;
          103 
          104   m_unit = ut_clone(other.m_unit);
          105   if (m_unit == NULL) {
          106     throw RuntimeError(PISM_ERROR_LOCATION, "ut_clone failed");
          107   }
          108 
          109   return *this;
          110 }
          111 
          112 Unit::~Unit() {
          113   reset();
          114 }
          115 
          116 std::string Unit::format() const {
          117   return m_unit_string;
          118 }
          119 
          120 void Unit::reset() {
          121   ut_free(m_unit);
          122   m_unit = NULL;
          123 }
          124 
          125 ut_unit* Unit::get() const {
          126   return m_unit;
          127 }
          128 
          129 System::Ptr Unit::get_system() const {
          130   return m_system;
          131 }
          132 
          133 Converter::Converter() {
          134   m_converter = cv_get_trivial();
          135 }
          136 
          137 Converter::Converter(System::Ptr sys,
          138                      const std::string &spec1, const std::string &spec2) {
          139 
          140   Unit u1(sys, spec1), u2(sys, spec2);
          141 
          142   if (ut_are_convertible(u1.get(), u2.get()) == 0) {
          143     throw RuntimeError::formatted(PISM_ERROR_LOCATION, "cannot convert '%s' to '%s'", spec1.c_str(), spec2.c_str());
          144   }
          145 
          146   m_converter = ut_get_converter(u1.get(), u2.get());
          147   if (m_converter == NULL) {
          148     throw RuntimeError::formatted(PISM_ERROR_LOCATION, "cannot create a converter from %s to %s",
          149                                   spec1.c_str(), spec2.c_str());
          150   }
          151 }
          152 
          153 Converter::Converter(const Unit &u1, const Unit &u2) {
          154   if (ut_are_convertible(u1.get(), u2.get()) == 0) {
          155     throw RuntimeError::formatted(PISM_ERROR_LOCATION, "cannot convert '%s' to '%s'",
          156                                   u1.format().c_str(), u2.format().c_str());
          157   }
          158 
          159   m_converter = ut_get_converter(u1.get(), u2.get());
          160   if (m_converter == NULL) {
          161     throw RuntimeError::formatted(PISM_ERROR_LOCATION, "failed to create a converter from '%s' to '%s'",
          162                                   u1.format().c_str(), u2.format().c_str());
          163   }
          164 }
          165 
          166 bool are_convertible(const Unit &u1, const Unit &u2) {
          167   return ut_are_convertible(u1.get(), u2.get()) != 0;
          168 }
          169 
          170 Converter::~Converter() {
          171   cv_free(m_converter);
          172   m_converter = NULL;
          173 }
          174 
          175 double Converter::operator()(double input) const {
          176   return cv_convert_double(m_converter, input);
          177 }
          178 
          179 void Converter::convert_doubles(double *data, size_t length) const {
          180   cv_convert_doubles(m_converter, data, length, data);
          181 }
          182 
          183 } // end of namespace units
          184 
          185 } // end of namespace pism