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