1 // Reaktoro is a unified framework for modeling chemically reactive systems.
2 //
3 // Copyright (C) 2014-2015 Allan Leal
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 #ifndef THERMOSCALAR_H
19 #define THERMOSCALAR_H
20
21
22 // C++ includes
23 #include <cmath>
24 #include <iostream>
25
26 namespace Reaktoro_ {
27
28 enum Status {
29 notdefined = 0,
30 read,
31 calculated,
32 assigned,
33 initialized
34 };
35
36 using StatusMessage = std::pair <Status, std::string>;
37
38 /// A template base class to represent a thermodynamic scalar and its partial derivatives.
39 /// A *thermodynamic property* is a quantity that depends on temperature and pressure.
40 /// @see ThermoScalar, ChemicalScalar, ThermoVector
41 template<typename V>
42 class ThermoScalarBase
43 {
44 public:
45 /// The value of the thermodynamic property.
46 V val;
47
48 /// The partial temperature derivative of the thermodynamic property.
49 V ddt;
50
51 /// The partial pressure derivative of the thermodynamic property.
52 V ddp;
53
54 /// The error of the value of the thermodynamic property
55 V err;
56
57 /// The status of the themrodyanic property
58 StatusMessage sta;
59
60 /// Construct a default ThermoScalar instance
ThermoScalarBase()61 ThermoScalarBase()
62 : ThermoScalarBase(0.0) {}
63
64 /// Construct a custom ThermoScalarBase instance with given value only.
65 /// @param val The value of the thermodynamic property
ThermoScalarBase(double val)66 explicit ThermoScalarBase(double val)
67 : ThermoScalarBase(val, 0.0, 0.0, 0.0, {Status::notdefined, ""}) {}
68
69 /// Construct a custom ThermoScalarBase instance with given value and derivatives.
70 /// @param val The value of the thermodynamic property
71 /// @param ddt The partial temperature derivative of the thermodynamic property
72 /// @param ddp The partial pressure derivative of the thermodynamic property
73 /// @param err The error of the value of the thermodynamic property
ThermoScalarBase(const V & val,const V & ddt,const V & ddp,const V & err,const StatusMessage & sta)74 ThermoScalarBase(const V& val, const V& ddt, const V& ddp, const V& err, const StatusMessage& sta)
75 : val(val), ddt(ddt), ddp(ddp), err(fabs(err)), sta(sta) {}
76
77 /// Construct a copy of a ThermoScalar instance.
78 template<typename VR>
ThermoScalarBase(const ThermoScalarBase<VR> & other)79 ThermoScalarBase(const ThermoScalarBase<VR>& other)
80 : val(other.val), ddt(other.ddt), ddp(other.ddp), err(other.err), sta(other.sta) {}
81
82 /// Assign another ThermoScalarBase instance to this ThermoScalarBase instance.
83 template<typename VR>
operator =(const ThermoScalarBase<VR> & other)84 ThermoScalarBase& operator=(const ThermoScalarBase<VR>& other)
85 {
86 val = other.val;
87 ddt = other.ddt;
88 ddp = other.ddp;
89 err = other.err;
90 sta = other.sta;
91 return *this;
92 }
93
94 /// Assign a scalar to this ThermoScalarBase instance.
operator =(double other)95 ThermoScalarBase& operator=(double other)
96 {
97 val = other;
98 ddt = 0.0;
99 ddp = 0.0;
100 err = 0.0;
101 sta = {Status::assigned, std::string("")};
102 return *this;
103 }
104
105 /// Assign-addition of a ThermoScalar instance
106 template<typename VR>
operator +=(const ThermoScalarBase<VR> & other)107 ThermoScalarBase& operator+=(const ThermoScalarBase<VR>& other)
108 {
109 val += other.val;
110 ddt += other.ddt;
111 ddp += other.ddp;
112 err = std::sqrt(err*err + other.err*other.err);
113
114 if (sta.first == Status::notdefined || other.sta.first == Status::notdefined)
115 sta = {Status::notdefined, std::string("")};
116 else
117 sta = {Status::calculated, std::string("")};
118
119 return *this;
120 }
121
122 /// Assign-subtraction of a ThermoScalar instance
123 template<typename VR>
operator -=(const ThermoScalarBase<VR> & other)124 ThermoScalarBase& operator-=(const ThermoScalarBase<VR>& other)
125 {
126 val -= other.val;
127 ddt -= other.ddt;
128 ddp -= other.ddp;
129 err = std::sqrt(err*err + other.err*other.err);
130
131 if (sta.first == Status::notdefined || other.sta.first == Status::notdefined)
132 sta = {Status::notdefined, std::string("")};
133 else
134 sta = {Status::calculated, std::string("")};
135
136 return *this;
137 }
138
139 /// Assign-multiplication of a ThermoScalar instance
140 template<typename VR>
operator *=(const ThermoScalarBase<VR> & other)141 ThermoScalarBase& operator*=(const ThermoScalarBase<VR>& other)
142 {
143 const double tmp_err = err / val;
144 ddt = ddt * other.val + val * other.ddt;
145 ddp = ddp * other.val + val * other.ddp;
146 val *= other.val;
147 if (other.val == 0)
148 err = 0.0;
149 else
150 err = val*sqrt(tmp_err*tmp_err + other.err/other.val*other.err/other.val);
151
152 if (sta.first == Status::notdefined || other.sta.first == Status::notdefined)
153 sta = {Status::notdefined, std::string("")};
154 else
155 sta = {Status::calculated, std::string("")};
156
157 return *this;
158 }
159
160 /// Assign-division of a ThermoScalar instance
161 template<typename VR>
operator /=(const ThermoScalarBase<VR> & other)162 ThermoScalarBase& operator/=(const ThermoScalarBase<VR>& other)
163 {
164 const double tmp1 = 1.0/other.val;
165 const double tmp2 = tmp1 * tmp1;
166 const double tmp_err = err / val;
167 ddt = (ddt * other.val - val * other.ddt) * tmp2;
168 ddp = (ddp * other.val - val * other.ddp) * tmp2;
169 val *= tmp1;
170 if (other.val == 0)
171 err = 0.0;
172 else
173 err = val*sqrt(tmp_err*tmp_err + other.err/other.val*other.err/other.val);
174
175 if (sta.first == Status::notdefined || other.sta.first == Status::notdefined)
176 sta = {Status::notdefined, std::string("")};
177 else
178 sta = {Status::calculated, std::string("")};
179
180 return *this;
181 }
182
183 /// Assign-addition of a scalar
operator +=(double other)184 ThermoScalarBase& operator+=(double other)
185 {
186 val += other;
187 return *this;
188 }
189
190 /// Assign-subtraction of a scalar
operator -=(double other)191 ThermoScalarBase& operator-=(double other)
192 {
193 val -= other;
194 return *this;
195 }
196
197 /// Assign-multiplication of a ThermoScalar instance
operator *=(double other)198 ThermoScalarBase& operator*=(double other)
199 {
200 const double tmp_err = err/val*err/val;
201 val *= other;
202 ddt *= other;
203 ddp *= other;
204 if (val == 0)
205 err = 0.0;
206 else
207 err = val*std::sqrt(tmp_err);
208 return *this;
209 }
210
211 /// Assign-division of a ThermoScalar instance
operator /=(double other)212 ThermoScalarBase& operator/=(double other)
213 {
214 const double tmp_err = err/val*err/val;
215 *this *= 1.0/other;
216 if (val == 0)
217 err = 0.0;
218 else
219 err = val*std::sqrt(tmp_err);
220 return *this;
221 }
222
223 /// Explicitly converts this ThermoScalar instance into a double.
operator double()224 explicit operator double()
225 {
226 return val;
227 }
228 };
229
230 /// A type that defines a scalar thermo property.
231 /// A thermo property means here any property that depends on
232 /// temperature and pressure. A ThermoScalar instance not only holds
233 /// the value of the thermo property, but also is partial
234 /// temperature and pressure derivatives.
235 /// @see ChemicalVector
236 using ThermoScalar = ThermoScalarBase<double>;
237
238 /// A type that describes temperature in units of K
239 class Temperature : public ThermoScalar
240 {
241 public:
242 /// Construct a default Temperature instance
Temperature()243 Temperature() : Temperature(0.0) {}
244
245 /// Construct a Temperature instance with given value
Temperature(double val)246 Temperature(double val) : ThermoScalarBase(val, 1.0, 0.0, 0.0, {Status::assigned, std::string("")}) {}
247
248 /// Convert this Temperature instance into a double
249 // operator double() { return val; }
250 };
251
252 /// A type that describes pressure in units of Pa
253 class Pressure : public ThermoScalar
254 {
255 public:
256 /// Construct a default Pressure instance
Pressure()257 Pressure() : Pressure(0.0) {}
258
259 /// Construct a Pressure instance with given value
Pressure(double val)260 Pressure(double val) : ThermoScalarBase(val, 0.0, 1.0, 0.0, {Status::assigned, std::string("")}) {}
261
262 /// Convert this Pressure instance into a double
263 // operator double() { return val; }
264 };
265
266
267 template<typename VL, typename VR>
status(const ThermoScalarBase<VL> & l,const ThermoScalarBase<VR> & r)268 inline auto status(const ThermoScalarBase<VL>& l, const ThermoScalarBase<VR>& r) -> StatusMessage
269 {
270 if (l.sta.first == Status::notdefined || r.sta.first == Status::notdefined)
271 return {Status::notdefined, std::string("")};
272 else
273 return {Status::calculated, std::string("")};
274 }
275 template<typename VL>
status(const ThermoScalarBase<VL> & l)276 inline auto status(const ThermoScalarBase<VL>& l) -> StatusMessage
277 {
278 if (l.sta.first == Status::notdefined)
279 return {Status::notdefined, std::string("")};
280 else
281 return {Status::calculated, std::string("")};
282 }
283 /// Unary addition operator for a ThermoScalar instance
284 template<typename V>
operator +(const ThermoScalarBase<V> & l)285 inline auto operator+(const ThermoScalarBase<V>& l) -> ThermoScalarBase<double>
286 {
287 l.sta = status(l);
288 return l;
289 }
290
291 /// Add two ThermoScalar instances
292 template<typename VL, typename VR>
operator +(const ThermoScalarBase<VL> & l,const ThermoScalarBase<VR> & r)293 inline auto operator+(const ThermoScalarBase<VL>& l, const ThermoScalarBase<VR>& r) -> ThermoScalarBase<double>
294 {
295 return {l.val + r.val, l.ddt + r.ddt, l.ddp + r.ddp, std::sqrt(l.err*l.err + r.err*r.err), status(l,r)};
296 }
297
298 template<typename V>
operator +(double l,const ThermoScalarBase<V> & r)299 inline auto operator+(double l, const ThermoScalarBase<V>& r) -> ThermoScalarBase<double>
300 {
301 return {l + r.val, r.ddt, r.ddp, r.err, status(r)};
302 }
303
304 template<typename V>
operator +(const ThermoScalarBase<V> & l,double r)305 inline auto operator+(const ThermoScalarBase<V>& l, double r) -> ThermoScalarBase<double>
306 {
307 return r + l;
308 }
309
310 /// Unary subtraction operator for a ThermoScalar instance
311 template<typename V>
operator -(const ThermoScalarBase<V> & l)312 inline auto operator-(const ThermoScalarBase<V>& l) -> ThermoScalarBase<double>
313 {
314 return {-l.val, -l.ddt, -l.ddp, +(std::sqrt(l.err*l.err)), status(l)};
315 }
316
317 /// Subtract two ThermoScalar instances
318 template<typename VL, typename VR>
operator -(const ThermoScalarBase<VL> & l,const ThermoScalarBase<VR> & r)319 inline auto operator-(const ThermoScalarBase<VL>& l, const ThermoScalarBase<VR>& r) -> ThermoScalarBase<double>
320 {
321 return {l.val - r.val, l.ddt - r.ddt, l.ddp - r.ddp, std::sqrt(l.err*l.err + r.err*r.err), status(l, r)};
322 }
323
324 /// Right-subtract a ThermoScalar instance by a scalar
325 template<typename V>
operator -(const ThermoScalarBase<V> & l,double r)326 inline auto operator-(const ThermoScalarBase<V>& l, double r) -> ThermoScalarBase<double>
327 {
328 return {l.val - r, l.ddt, l.ddp, l.err, status(l)};
329 }
330
331 /// Left-subtract a ThermoScalar instance by a scalar
332 template<typename V>
operator -(double l,const ThermoScalarBase<V> & r)333 inline auto operator-(double l, const ThermoScalarBase<V>& r) -> ThermoScalarBase<double>
334 {
335 return {l - r.val, -r.ddt, -r.ddp, r.err, status(r)};
336 }
337
338 /// Multiply two ThermoScalar instances
339 template<typename VL, typename VR>
operator *(const ThermoScalarBase<VL> & l,const ThermoScalarBase<VR> & r)340 inline auto operator*(const ThermoScalarBase<VL>& l, const ThermoScalarBase<VR>& r) -> ThermoScalarBase<double>
341 {
342 double a = 0.0; double b = 0.0;
343 if (l.val != 0)
344 a = l.err/l.val*l.err/l.val;
345 if (r.val != 0)
346 b = r.err/r.val*r.err/r.val;
347 return {l.val * r.val, l.val * r.ddt + l.ddt * r.val, l.val * r.ddp + l.ddp * r.val, (l.val * r.val)*std::sqrt(a+b), status(l,r)};
348 }
349
350 /// Left-multiply a ThermoScalar instance by a scalar
351 template<typename V>
operator *(double l,const ThermoScalarBase<V> & r)352 inline auto operator*(double l, const ThermoScalarBase<V>& r) -> ThermoScalarBase<double>
353 {
354 if (r.val == 0)
355 return {l * r.val, l * r.ddt, l * r.ddp, 0.0, status(r)};
356 auto err = (l * r.val)*std::sqrt(r.err/r.val*r.err/r.val);
357 return {l * r.val, l * r.ddt, l * r.ddp, err, status(r)};
358 }
359
360 /// Right-multiply a ThermoScalar instance by a scalar
361 template<typename V>
operator *(const ThermoScalarBase<V> & l,double r)362 inline auto operator*(const ThermoScalarBase<V>& l, double r) -> ThermoScalarBase<double>
363 {
364 return r * l;
365 }
366
367 /// Divide a ThermoScalar instance by another
368 template<typename VL, typename VR>
operator /(const ThermoScalarBase<VL> & l,const ThermoScalarBase<VR> & r)369 inline auto operator/(const ThermoScalarBase<VL>& l, const ThermoScalarBase<VR>& r) -> ThermoScalarBase<double>
370 {
371 const double tmp1 = 1.0/r.val;
372 const double tmp2 = tmp1 * tmp1;
373 double a = 0.0; double b = 0.0;
374 if (l.val != 0)
375 a = l.err/l.val*l.err/l.val;
376 if (r.val != 0)
377 b = r.err/r.val*r.err/r.val;
378 return {tmp1 * l.val, tmp2 * (l.ddt * r.val - l.val * r.ddt), tmp2 * (l.ddp * r.val - l.val * r.ddp), (tmp1 * l.val)*std::sqrt(a+b), status(l,r)};
379 }
380
381 /// Left-divide a ThermoScalar instance by a scalar
382 template<typename V>
operator /(double l,const ThermoScalarBase<V> & r)383 inline auto operator/(double l, const ThermoScalarBase<V>& r) -> ThermoScalarBase<double>
384 {
385 const double tmp1 = 1.0/r.val;
386 const double tmp2 = -l*tmp1*tmp1;
387 if (r.val == 0)
388 return {tmp1 * l, tmp2 * r.ddt, tmp2 * r.ddp, 0.0, status(r)};
389 return {tmp1 * l, tmp2 * r.ddt, tmp2 * r.ddp, (tmp1 * r.val)*std::sqrt(r.err/r.val*r.err/r.val), status(r)};
390 }
391
392 /// Right-divide a ThermoScalar instance by a scalar
393 template<typename V>
operator /(const ThermoScalarBase<V> & l,double r)394 inline auto operator/(const ThermoScalarBase<V>& l, double r) -> ThermoScalarBase<double>
395 {
396 return (1.0/r) * l;
397 }
398
399 /// Return the square root of a ThermoScalar instance
400 template<typename V>
sqrt(const ThermoScalarBase<V> & l)401 inline auto sqrt(const ThermoScalarBase<V>& l) -> ThermoScalarBase<double>
402 {
403 const double tmp1 = std::sqrt(l.val);
404 const double tmp2 = 0.5 * tmp1/l.val;
405 if (l.val == 0)
406 return {tmp1, /*tmp2 * l.ddt, tmp2 * l.ddp,*/ 0.0,0.0,0.0, status(l)};
407 return {tmp1, tmp2 * l.ddt, tmp2 * l.ddp, 0.5*(l.err/l.val), status(l)};
408 }
409
410 /// Return the power of a ThermoScalar instance
411 template<typename V>
pow(const ThermoScalarBase<V> & l,double power)412 inline auto pow(const ThermoScalarBase<V>& l, double power) -> ThermoScalarBase<double>
413 {
414 const double tmp1 = std::pow(l.val, power);
415 const double tmp2 = power * tmp1/l.val;
416 if (l.val == 0)
417 return {tmp1, /*tmp2 * l.ddt, tmp2 * l.ddp,*/0.0,0.0, 0.0, status(l)};
418 return {tmp1, tmp2 * l.ddt, tmp2 * l.ddp, std::fabs(power)*(l.err/l.val), status(l)};
419 }
420
421 /// Return the power of a ThermoScalar instance
422 template<typename VL, typename VR>
pow(const ThermoScalarBase<VL> & l,const ThermoScalarBase<VR> & power)423 inline auto pow(const ThermoScalarBase<VL>& l, const ThermoScalarBase<VR>& power) -> ThermoScalarBase<double>
424 {
425 const double logl = std::log(l.val);
426 const double powl = std::pow(l.val, power.val);
427 const double tmp = power.val/l.val;
428 if (l.val == 0)
429 return {powl, powl * (logl * power.ddt + /*tmp * l.ddt*/0.0), powl * (logl * power.ddp + /*tmp * l.ddp*/0.0), 0.0, status(l,power)};
430 return {powl, powl * (logl * power.ddt + tmp * l.ddt), powl * (logl * power.ddp + tmp * l.ddp), powl*(l.err/l.val), status(l,power)};
431 }
432
433 /// Return the natural exponential of a ThermoScalar instance
434 template<typename V>
exp(const ThermoScalarBase<V> & l)435 inline auto exp(const ThermoScalarBase<V>& l) -> ThermoScalarBase<double>
436 {
437 const double tmp = std::exp(l.val);
438 return {tmp, tmp * l.ddt, tmp * l.ddp, l.err*tmp, status(l)};
439 }
440
441 /// Return the natural log of a ThermoScalar instance
442 template<typename V>
log(const ThermoScalarBase<V> & l)443 inline auto log(const ThermoScalarBase<V>& l) -> ThermoScalarBase<double>
444 {
445 const double tmp1 = std::log(l.val);
446 const double tmp2 = 1.0/l.val;
447 if (l.val == 0)
448 return {tmp1, /*tmp2 * l.ddt, tmp2 * l.ddp,*/ 0.0,0.0, 0.0, status(l)};
449 return {tmp1, tmp2 * l.ddt, tmp2 * l.ddp, 0.434*(l.err/l.val), status(l)};
450 }
451
452 /// Return the log10 of a ThermoScalar instance
453 template<typename V>
log10(const ThermoScalarBase<V> & l)454 inline auto log10(const ThermoScalarBase<V>& l) -> ThermoScalarBase<double>
455 {
456 const double ln10 = 2.302585092994046;
457 return log(l)/ln10;
458 }
459
460 /// Return true if a ThermoScalar instance is less than another
461 template<typename VL, typename VR>
operator <(const ThermoScalarBase<VL> & l,const ThermoScalarBase<VR> & r)462 inline auto operator<(const ThermoScalarBase<VL>& l, const ThermoScalarBase<VR>& r) -> bool
463 {
464 return l.val < r.val;
465 }
466
467 /// Return true if a ThermoScalar instance is less or equal than another
468 template<typename VL, typename VR>
operator <=(const ThermoScalarBase<VL> & l,const ThermoScalarBase<VR> & r)469 inline auto operator<=(const ThermoScalarBase<VL>& l, const ThermoScalarBase<VR>& r) -> bool
470 {
471 return l.val <= r.val;
472 }
473
474 /// Return true if a ThermoScalar instance is greater than another
475 template<typename VL, typename VR>
operator >(const ThermoScalarBase<VL> & l,const ThermoScalarBase<VR> & r)476 inline auto operator>(const ThermoScalarBase<VL>& l, const ThermoScalarBase<VR>& r) -> bool
477 {
478 return l.val > r.val;
479 }
480
481 /// Return true if a ThermoScalar instance is greater or equal than another
482 template<typename VL, typename VR>
operator >=(const ThermoScalarBase<VL> & l,const ThermoScalarBase<VR> & r)483 inline auto operator>=(const ThermoScalarBase<VL>& l, const ThermoScalarBase<VR>& r) -> bool
484 {
485 return l.val >= r.val;
486 }
487
488 /// Return true if a ThermoScalar instance is equal to another
489 template<typename VL, typename VR>
operator ==(const ThermoScalarBase<VL> & l,const ThermoScalarBase<VR> & r)490 inline auto operator==(const ThermoScalarBase<VL>& l, const ThermoScalarBase<VR>& r) -> bool
491 {
492 return l.val == r.val;
493 }
494
495 /// Return true if a ThermoScalar instance is not equal to another
496 template<typename VL, typename VR>
operator !=(const ThermoScalarBase<VL> & l,const ThermoScalarBase<VR> & r)497 inline auto operator!=(const ThermoScalarBase<VL>& l, const ThermoScalarBase<VR>& r) -> bool
498 {
499 return l.val != r.val;
500 }
501
502 /// Return true if a scalar is less than a ThermoScalar instance
503 template<typename V>
operator <(double l,const ThermoScalarBase<V> & r)504 inline auto operator<(double l, const ThermoScalarBase<V>& r) -> bool
505 {
506 return l < r.val;
507 }
508
509 /// Return true if a ThermoScalar instance is less than a scalar
510 template<typename V>
operator <(const ThermoScalarBase<V> & l,double r)511 inline auto operator<(const ThermoScalarBase<V>& l, double r) -> bool
512 {
513 return l.val < r;
514 }
515
516 /// Return true if a scalar is less or equal than a ThermoScalar instance
517 template<typename V>
operator <=(double l,const ThermoScalarBase<V> & r)518 inline auto operator<=(double l, const ThermoScalarBase<V>& r) -> bool
519 {
520 return l <= r.val;
521 }
522
523 /// Return true if a ThermoScalar instance is less or equal than a scalar
524 template<typename V>
operator <=(const ThermoScalarBase<V> & l,double r)525 inline auto operator<=(const ThermoScalarBase<V>& l, double r) -> bool
526 {
527 return l.val <= r;
528 }
529
530 /// Return true if a scalar is greater than a ThermoScalar instance
531 template<typename V>
operator >(double l,const ThermoScalarBase<V> & r)532 inline auto operator>(double l, const ThermoScalarBase<V>& r) -> bool
533 {
534 return l > r.val;
535 }
536
537 /// Return true if a ThermoScalar is greater than a scalar
538 template<typename V>
operator >(const ThermoScalarBase<V> & l,double r)539 inline auto operator>(const ThermoScalarBase<V>& l, double r) -> bool
540 {
541 return l.val > r;
542 }
543
544 /// Return true if a scalar is greater or equal than a ThermoScalar instance
545 template<typename V>
operator >=(double l,const ThermoScalarBase<V> & r)546 inline auto operator>=(double l, const ThermoScalarBase<V>& r) -> bool
547 {
548 return l >= r.val;
549 }
550
551 /// Return true if a ThermoScalar instance is greater or equal than a scalar
552 template<typename V>
operator >=(const ThermoScalarBase<V> & l,double r)553 inline auto operator>=(const ThermoScalarBase<V>& l, double r) -> bool
554 {
555 return l.val >= r;
556 }
557
558 /// Return true if a scalar is equal to a ThermoScalar instance
559 template<typename V>
operator ==(double l,const ThermoScalarBase<V> & r)560 inline auto operator==(double l, const ThermoScalarBase<V>& r) -> bool
561 {
562 return l == r.val;
563 }
564
565 /// Return true if a ThermoScalar instance is equal to a scalar
566 template<typename V>
operator ==(const ThermoScalarBase<V> & l,double r)567 inline auto operator==(const ThermoScalarBase<V>& l, double r) -> bool
568 {
569 return l.val == r;
570 }
571
572 /// Return true if a scalar is not equal to a ThermoScalar instance
573 template<typename V>
operator !=(double l,const ThermoScalarBase<V> & r)574 inline auto operator!=(double l, const ThermoScalarBase<V>& r) -> bool
575 {
576 return l != r.val;
577 }
578
579 /// Return true if a ThermoScalar instance is not equal to a scalar
580 template<typename V>
operator !=(const ThermoScalarBase<V> & l,double r)581 inline auto operator!=(const ThermoScalarBase<V>& l, double r) -> bool
582 {
583 return l.val != r;
584 }
585
586 /// Output a ThermoScalar instance
587 template<typename V>
operator <<(std::ostream & out,const ThermoScalarBase<V> & scalar)588 inline auto operator<<(std::ostream& out, const ThermoScalarBase<V>& scalar) -> std::ostream&
589 {
590 out << scalar.val;
591 return out;
592 }
593
594 } // namespace Reaktoro
595
596 #endif // THERMOSCALAR_H
597