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