TBTK
Need a break? Support the development by playing Polarity Puzzles
UnitHandler.h
Go to the documentation of this file.
1 /* Copyright 2016 Kristofer Björnson
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
23 #ifndef COM_DAFER45_TBTK_UNIT_HANDLER
24 #define COM_DAFER45_TBTK_UNIT_HANDLER
25 
26 #include "TBTK/TBTK.h"
27 #include "TBTK/Quantity/Constant.h"
28 #include "TBTK/Quantity/Derived.h"
29 #include "TBTK/TBTKMacros.h"
30 
31 #include <cmath>
32 #include <map>
33 #include <string>
34 #include <utility>
35 #include <vector>
36 
37 #ifdef M_E //Avoid name clash with math.h macro M_E
38  #define M_E_temp M_E
39  #undef M_E
40 #endif
41 
42 namespace TBTK{
43 
192 public:
194  static double getConstantInBaseUnits(const std::string &name);
195 
197  static double getConstantInNaturalUnits(const std::string &name);
198 
200  static void setScales(const std::vector<std::string> &scales);
201 
203  template<typename Quantity>
204  static double convertNaturalToBase(double value);
205 
207  template<typename Quantity>
208  static double convertBaseToNatural(double value);
209 
213  template<typename Quantity>
214  static typename std::enable_if<
215  Quantity::IsBaseQuantity::value,
216  double
217  >::type convertArbitraryToBase(
218  double value,
219  typename Quantity::Unit unit
220  );
221  template<typename Quantity>
222  static typename std::enable_if<
223  !Quantity::IsBaseQuantity::value,
224  double
225  >::type convertArbitraryToBase(
226  double value,
227  typename Quantity::Unit unit
228  );
234  template<typename Quantity>
235  static typename std::enable_if<
236  Quantity::IsBaseQuantity::value,
237  double
238  >::type convertBaseToArbitrary(
239  double value,
240  typename Quantity::Unit unit
241  );
242  template<typename Quantity>
243  static typename std::enable_if<
244  !Quantity::IsBaseQuantity::value,
245  double
246  >::type convertBaseToArbitrary(
247  double value,
248  typename Quantity::Unit unit
249  );
255  template<typename Quantity>
256  static typename std::enable_if<
257  Quantity::IsBaseQuantity::value,
258  double
259  >::type convertArbitraryToNatural(
260  double value,
261  typename Quantity::Unit unit
262  );
263  template<typename Quantity>
264  static typename std::enable_if<
265  !Quantity::IsBaseQuantity::value,
266  double
267  >::type convertArbitraryToNatural(
268  double value,
269  typename Quantity::Unit unit
270  );
276  template<typename Quantity>
277  static typename std::enable_if<
278  Quantity::IsBaseQuantity::value,
279  double
280  >::type convertNaturalToArbitrary(
281  double value,
282  typename Quantity::Unit unit
283  );
284  template<typename Quantity>
285  static typename std::enable_if<
286  !Quantity::IsBaseQuantity::value,
287  double
288  >::type convertNaturalToArbitrary(
289  double value,
290  typename Quantity::Unit unit
291  );
301  template<typename Quantity>
302  static typename std::enable_if<
303  Quantity::IsBaseQuantity::value,
304  std::string
305  >::type getUnitString();
306  template<typename Quantity>
307  static typename std::enable_if<
308  !Quantity::IsBaseQuantity::value,
309  std::string
310  >::type getUnitString();
318  static std::string getUnitString(const std::string &constantName);
319 private:
321  static std::map<
322  std::string,
323  Quantity::Constant
324  > constantsDefaultUnits;
325 
327  static std::map<std::string, double> constantsBaseUnits;
328 
330  static std::tuple<
331  Quantity::Angle::Unit,
332  Quantity::Charge::Unit,
333  Quantity::Count::Unit,
334  Quantity::Energy::Unit,
335  Quantity::Length::Unit,
336  Quantity::Temperature::Unit,
337  Quantity::Time::Unit
338  > units;
339 
341  static std::tuple<
342  double,
343  double,
344  double,
345  double,
346  double,
347  double,
348  double
349  > scales;
350 
352  template<typename Quantity>
353  static void setUnit(typename Quantity::Unit unit);
354 
357  template<typename Quantity>
358  static typename std::enable_if<
359  Quantity::IsBaseQuantity::value,
360  typename Quantity::Unit&
361  >::type getUnit();
362 
364  template<typename Quantity>
365  static void setScale(double scale);
366 
369  template<typename Quantity>
370  static double& getScale();
371 
373  template<typename Quantity>
374  static void setScale(double scale, typename Quantity::Unit unit);
375 
377  template<typename Quantity>
378  static void setScale(const std::string &scale);
379 
381  static void updateConstants();
382 
385  template<typename Quantity>
386  static double getConversionFactor();
387 
390  template<typename Quantity>
391  static double getConversionFactor(typename Quantity::Unit unit);
392 
394  template<typename Quantity>
395  static typename Quantity::Unit getUnit(const std::string &unit);
396 
399  static std::string getUnitString(
400  int angleExponent,
401  int chargeExponent,
402  int countExponent,
403  int energyExponent,
404  int lengthExponent,
405  int temperatureExponent,
406  int timeExponent
407  );
408 
411  template<typename Quantity>
412  static typename std::enable_if<
413  Quantity::IsBaseQuantity::value,
414  std::string
415  >::type getUnitString(int exponent);
416 
418  static void initialize();
419 
422  friend void Initialize();
423 };
424 
425 template<typename Quantity>
426 void UnitHandler::setUnit(typename Quantity::Unit unit){
427  double oldConversionFactor = getConversionFactor<Quantity>();
428  getUnit<Quantity>() = unit;
429  double newConversionFactor = getConversionFactor<Quantity>();
430  getScale<Quantity>() *= newConversionFactor/oldConversionFactor;
431  updateConstants();
432 }
433 
434 template<>
435 inline Quantity::Angle::Unit& UnitHandler::getUnit<Quantity::Angle>(
436 ){
437  return std::get<0>(units);
438 }
439 
440 template<>
441 inline Quantity::Charge::Unit& UnitHandler::getUnit<Quantity::Charge>(
442 ){
443  return std::get<1>(units);
444 }
445 
446 template<>
447 inline Quantity::Count::Unit& UnitHandler::getUnit<Quantity::Count>(
448 ){
449  return std::get<2>(units);
450 }
451 
452 template<>
453 inline Quantity::Energy::Unit& UnitHandler::getUnit<Quantity::Energy>(
454 ){
455  return std::get<3>(units);
456 }
457 
458 template<>
459 inline Quantity::Length::Unit& UnitHandler::getUnit<Quantity::Length>(
460 ){
461  return std::get<4>(units);
462 }
463 
464 template<>
465 inline Quantity::Temperature::Unit& UnitHandler::getUnit<
466  Quantity::Temperature
467 >(){
468  return std::get<5>(units);
469 }
470 
471 template<>
472 inline Quantity::Time::Unit& UnitHandler::getUnit<Quantity::Time>(
473 ){
474  return std::get<6>(units);
475 }
476 
477 template <typename Quantity>
478 void UnitHandler::setScale(double scale, typename Quantity::Unit unit){
479  setUnit<Quantity>(unit);
480  setScale<Quantity>(scale);
481 }
482 
483 inline void UnitHandler::setScales(const std::vector<std::string> &scales){
484  TBTKAssert(
485  scales.size() == 7,
486  "UnitHandler::setScales()",
487  "'scales' must contain seven strings.",
488  ""
489  );
490 
491  setScale<Quantity::Angle>(scales[0]);
492  setScale<Quantity::Charge>(scales[1]);
493  setScale<Quantity::Count>(scales[2]);
494  setScale<Quantity::Energy>(scales[3]);
495  setScale<Quantity::Length>(scales[4]);
496  setScale<Quantity::Temperature>(scales[5]);
497  setScale<Quantity::Time>(scales[6]);
498  updateConstants();
499 }
500 
501 template<typename Quantity>
503  return value*getScale<Quantity>();
504 }
505 
506 template<typename Quantity>
508  return value/getScale<Quantity>();
509 }
510 
511 template<typename Quantity>
512 typename std::enable_if<
513  Quantity::IsBaseQuantity::value,
514  double
515 >::type UnitHandler::convertArbitraryToBase(
516  double value,
517  typename Quantity::Unit unit
518 ){
519  return value*getConversionFactor<Quantity>(
520  )/getConversionFactor<Quantity>(unit);
521 }
522 
523 template<typename Quantity>
524 typename std::enable_if<
525  !Quantity::IsBaseQuantity::value,
526  double
527 >::type UnitHandler::convertArbitraryToBase(
528  double value,
529  typename Quantity::Unit unit
530 ){
531  return value*Quantity::getConversionFactor(
532  getUnit<TBTK::Quantity::Angle>(),
533  getUnit<TBTK::Quantity::Charge>(),
534  getUnit<TBTK::Quantity::Count>(),
535  getUnit<TBTK::Quantity::Energy>(),
536  getUnit<TBTK::Quantity::Length>(),
537  getUnit<TBTK::Quantity::Temperature>(),
538  getUnit<TBTK::Quantity::Time>()
539  )/Quantity::getConversionFactor(unit);
540 }
541 
542 template<typename Quantity>
543 typename std::enable_if<
544  Quantity::IsBaseQuantity::value,
545  double
546 >::type UnitHandler::convertBaseToArbitrary(
547  double value,
548  typename Quantity::Unit unit
549 ){
550  return value*getConversionFactor<Quantity>(
551  unit
552  )/getConversionFactor<Quantity>();
553 }
554 
555 template<typename Quantity>
556 typename std::enable_if<
557  !Quantity::IsBaseQuantity::value,
558  double
559 >::type UnitHandler::convertBaseToArbitrary(
560  double value,
561  typename Quantity::Unit unit
562 ){
563  return value*Quantity::getConversionFactor(
564  unit
565  )/Quantity::getConversionFactor(
566  getUnit<TBTK::Quantity::Angle>(),
567  getUnit<TBTK::Quantity::Charge>(),
568  getUnit<TBTK::Quantity::Count>(),
569  getUnit<TBTK::Quantity::Energy>(),
570  getUnit<TBTK::Quantity::Length>(),
571  getUnit<TBTK::Quantity::Temperature>(),
572  getUnit<TBTK::Quantity::Time>()
573  );
574 }
575 
576 template<typename Quantity>
577 typename std::enable_if<
578  Quantity::IsBaseQuantity::value,
579  double
580 >::type UnitHandler::convertArbitraryToNatural(
581  double value,
582  typename Quantity::Unit unit
583 ){
584  return value*getConversionFactor<Quantity>(
585  )/(getConversionFactor<Quantity>(unit)*getScale<Quantity>());
586 }
587 
588 template<typename Quantity>
589 typename std::enable_if<
590  !Quantity::IsBaseQuantity::value,
591  double
592 >::type UnitHandler::convertArbitraryToNatural(
593  double value,
594  typename Quantity::Unit unit
595 ){
596  double result = value*Quantity::getConversionFactor(
597  getUnit<TBTK::Quantity::Angle>(),
598  getUnit<TBTK::Quantity::Charge>(),
599  getUnit<TBTK::Quantity::Count>(),
600  getUnit<TBTK::Quantity::Energy>(),
601  getUnit<TBTK::Quantity::Length>(),
602  getUnit<TBTK::Quantity::Temperature>(),
603  getUnit<TBTK::Quantity::Time>()
604  )/Quantity::getConversionFactor(unit);
605 
606  result /= pow(
607  getScale<TBTK::Quantity::Angle>(),
608  Quantity::getExponent(TBTK::Quantity::Angle())
609  );
610  result /= pow(
611  getScale<TBTK::Quantity::Charge>(),
612  Quantity::getExponent(TBTK::Quantity::Charge())
613  );
614  result /= pow(
615  getScale<TBTK::Quantity::Count>(),
616  Quantity::getExponent(TBTK::Quantity::Count())
617  );
618  result /= pow(
619  getScale<TBTK::Quantity::Energy>(),
620  Quantity::getExponent(TBTK::Quantity::Energy())
621  );
622  result /= pow(
623  getScale<TBTK::Quantity::Length>(),
624  Quantity::getExponent(TBTK::Quantity::Length())
625  );
626  result /= pow(
627  getScale<TBTK::Quantity::Temperature>(),
628  Quantity::getExponent(TBTK::Quantity::Temperature())
629  );
630  result /= pow(
631  getScale<TBTK::Quantity::Time>(),
632  Quantity::getExponent(TBTK::Quantity::Time())
633  );
634 
635  return result;
636 }
637 
638 template<typename Quantity>
639 typename std::enable_if<
640  Quantity::IsBaseQuantity::value,
641  double
642 >::type UnitHandler::convertNaturalToArbitrary(
643  double value,
644  typename Quantity::Unit unit
645 ){
646  return value*getScale<Quantity>()*getConversionFactor<Quantity>(
647  unit
648  )/getConversionFactor<Quantity>();
649 }
650 
651 template<typename Quantity>
652 typename std::enable_if<
653  !Quantity::IsBaseQuantity::value,
654  double
655 >::type UnitHandler::convertNaturalToArbitrary(
656  double value,
657  typename Quantity::Unit unit
658 ){
659  double result = value*Quantity::getConversionFactor(
660  unit
661  )/Quantity::getConversionFactor(
662  getUnit<TBTK::Quantity::Angle>(),
663  getUnit<TBTK::Quantity::Charge>(),
664  getUnit<TBTK::Quantity::Count>(),
665  getUnit<TBTK::Quantity::Energy>(),
666  getUnit<TBTK::Quantity::Length>(),
667  getUnit<TBTK::Quantity::Temperature>(),
668  getUnit<TBTK::Quantity::Time>()
669  );
670 
671  result *= pow(
672  getScale<TBTK::Quantity::Angle>(),
673  Quantity::getExponent(TBTK::Quantity::Angle())
674  );
675  result *= pow(
676  getScale<TBTK::Quantity::Charge>(),
677  Quantity::getExponent(TBTK::Quantity::Charge())
678  );
679  result *= pow(
680  getScale<TBTK::Quantity::Count>(),
681  Quantity::getExponent(TBTK::Quantity::Count())
682  );
683  result *= pow(
684  getScale<TBTK::Quantity::Energy>(),
685  Quantity::getExponent(TBTK::Quantity::Energy())
686  );
687  result *= pow(
688  getScale<TBTK::Quantity::Length>(),
689  Quantity::getExponent(TBTK::Quantity::Length())
690  );
691  result *= pow(
692  getScale<TBTK::Quantity::Temperature>(),
693  Quantity::getExponent(TBTK::Quantity::Temperature())
694  );
695  result *= pow(
696  getScale<TBTK::Quantity::Time>(),
697  Quantity::getExponent(TBTK::Quantity::Time())
698  );
699 
700  return result;
701 }
702 
703 template<typename Quantity>
704 double UnitHandler::getConversionFactor(){
705 
706  return Quantity::getConversionFactor(getUnit<Quantity>());
707 }
708 
709 template<typename Quantity>
710 double UnitHandler::getConversionFactor(typename Quantity::Unit unit){
711  return Quantity::getConversionFactor(unit);
712 }
713 
714 template<typename Quantity>
715 inline void UnitHandler::setScale(double scale){
716  getScale<Quantity>() = scale;
717 }
718 
719 template<typename Quantity>
720 inline void UnitHandler::setScale(const std::string &scale){
721  std::stringstream stream(scale);
722  std::vector<std::string> components;
723  std::string word;
724  while(std::getline(stream, word, ' '))
725  components.push_back(word);
726 
727  TBTKAssert(
728  components.size() == 2,
729  "UnitHandler::setScale()",
730  "Invalid scale string '" << scale << "'.",
731  "The string must be on the format '[scale] [unit]', e.g. '1 K'"
732  );
733 
734  double value;
735  try{
736  value = stod(components[0]);
737  }
738  catch(const std::exception &e){
739  TBTKExit(
740  "UnitHandler::setScale()",
741  "Unable to parse '" << components[0] << "' as a"
742  << " double.",
743  "The string has to be on the format '[scale] [unit]',"
744  << " e.g. '1 K'."
745  );
746  }
747 
748  typename Quantity::Unit unit = getUnit<Quantity>(components[1]);
749 
750  setScale<Quantity>(value, unit);
751 }
752 
753 template<>
754 inline double& UnitHandler::getScale<Quantity::Angle>(){
755  return std::get<0>(scales);
756 }
757 
758 template<>
759 inline double& UnitHandler::getScale<Quantity::Charge>(){
760  return std::get<1>(scales);
761 }
762 
763 template<>
764 inline double& UnitHandler::getScale<Quantity::Count>(){
765  return std::get<2>(scales);
766 }
767 
768 template<>
769 inline double& UnitHandler::getScale<Quantity::Energy>(){
770  return std::get<3>(scales);
771 }
772 
773 template<>
774 inline double& UnitHandler::getScale<Quantity::Length>(){
775  return std::get<4>(scales);
776 }
777 
778 template<>
779 inline double& UnitHandler::getScale<Quantity::Temperature>(){
780  return std::get<5>(scales);
781 }
782 
783 template<>
784 inline double& UnitHandler::getScale<Quantity::Time>(){
785  return std::get<6>(scales);
786 }
787 
788 template<typename Quantity>
789 inline typename std::enable_if<
790  Quantity::IsBaseQuantity::value,
791  std::string
792 >::type UnitHandler::getUnitString(){
793  return Quantity::getUnitString(getUnit<Quantity>());
794 }
795 
796 template<typename Quantity>
797 inline typename std::enable_if<
798  !Quantity::IsBaseQuantity::value,
799  std::string
800 >::type UnitHandler::getUnitString(){
801  return getUnitString(
802  static_cast<int>(Quantity::Exponent::Angle),
803  static_cast<int>(Quantity::Exponent::Charge),
804  static_cast<int>(Quantity::Exponent::Count),
805  static_cast<int>(Quantity::Exponent::Energy),
806  static_cast<int>(Quantity::Exponent::Length),
807  static_cast<int>(Quantity::Exponent::Temperature),
808  static_cast<int>(Quantity::Exponent::Time)
809  );
810 }
811 
812 template<typename Quantity>
813 typename Quantity::Unit UnitHandler::getUnit(const std::string &unit){
814  return Quantity::getUnit(unit);
815 }
816 
817 inline std::string UnitHandler::getUnitString(
818  int angleExponent,
819  int chargeExponent,
820  int countExponent,
821  int energyExponent,
822  int lengthExponent,
823  int temperatureExponent,
824  int timeExponent
825 ){
826  std::string result;
827  result += getUnitString<Quantity::Angle>(angleExponent);
828  result += getUnitString<Quantity::Charge>(chargeExponent);
829  result += getUnitString<Quantity::Count>(countExponent);
830  result += getUnitString<Quantity::Energy>(energyExponent);
831  result += getUnitString<Quantity::Length>(lengthExponent);
832  result += getUnitString<Quantity::Temperature>(temperatureExponent);
833  result += getUnitString<Quantity::Time>(timeExponent);
834 
835  if(result.size() != 0)
836  result.pop_back();
837 
838  return result;
839 }
840 
841 template<typename Quantity>
842 inline typename std::enable_if<
843  Quantity::IsBaseQuantity::value,
844  std::string
845 >::type UnitHandler::getUnitString(int exponent){
846  std::string result;
847  if(exponent != 0){
848  result += getUnitString<Quantity>();
849  if(exponent != 1)
850  result += "^" + std::to_string(exponent);
851  result += " ";
852  }
853  return result;
854 }
855 
856 };
857 
858 #ifdef M_E_temp //Avoid name clash with math.h macro M_E
859  #define M_E M_E_temp
860  #undef M_E_temp
861 #endif
862 
863 #endif
TBTK::UnitHandler::getConstantInBaseUnits
static double getConstantInBaseUnits(const std::string &name)
TBTK::UnitHandler::Initialize
friend void Initialize()
TBTK::Math::pow
Array< DataType > pow(const Array< DataType > &array, double exponent)
Definition: ArrayAlgorithms.h:747
TBTK::UnitHandler::setScales
static void setScales(const std::vector< std::string > &scales)
Definition: UnitHandler.h:483
TBTK::UnitHandler::convertNaturalToBase
static double convertNaturalToBase(double value)
Definition: UnitHandler.h:502
TBTKMacros.h
Precompiler macros.
Derived.h
Derived Quantity.
TBTK::UnitHandler::convertBaseToNatural
static double convertBaseToNatural(double value)
Definition: UnitHandler.h:507
TBTK::UnitHandler
Handles conversion between different units.
Definition: UnitHandler.h:191
TBTK.h
TBTK initialization.
TBTK::UnitHandler::getConstantInNaturalUnits
static double getConstantInNaturalUnits(const std::string &name)