nmie-wrapper.cc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. ///
  2. /// @file nmie-wrapper.cc
  3. /// @author Ladutenko Konstantin <kostyfisik at gmail (.) com>
  4. /// @date Tue Sep 3 00:38:27 2013
  5. /// @copyright 2013 Ladutenko Konstantin
  6. ///
  7. /// nmie-wrapper is free software: you can redistribute it and/or modify
  8. /// it under the terms of the GNU General Public License as published by
  9. /// the Free Software Foundation, either version 3 of the License, or
  10. /// (at your option) any later version.
  11. ///
  12. /// nmie-wrapper is distributed in the hope that it will be useful,
  13. /// but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. /// GNU General Public License for more details.
  16. ///
  17. /// You should have received a copy of the GNU General Public License
  18. /// along with nmie-wrapper. If not, see <http://www.gnu.org/licenses/>.
  19. ///
  20. /// nmie-wrapper uses nmie.c from scattnlay by Ovidio Pena
  21. /// <ovidio@bytesfall.com> as a linked library. He has an additional condition to
  22. /// his library:
  23. // The only additional condition is that we expect that all publications //
  24. // describing work using this software , or all commercial products //
  25. // using it, cite the following reference: //
  26. // [1] O. Pena and U. Pal, "Scattering of electromagnetic radiation by //
  27. // a multilayered sphere," Computer Physics Communications, //
  28. // vol. 180, Nov. 2009, pp. 2348-2354. //
  29. ///
  30. /// @brief Wrapper class around nMie function for ease of use
  31. ///
  32. #include "ucomplex.h"
  33. #include "nmie-wrapper.h"
  34. #include "nmie.h"
  35. #include <cstdio>
  36. #include <cstdlib>
  37. #include <stdexcept>
  38. #include <vector>
  39. namespace nmie {
  40. // ********************************************************************** //
  41. // ********************************************************************** //
  42. // ********************************************************************** //
  43. void MultiLayerMie::SetSizeParameter(std::vector<double> size_parameter) {
  44. size_parameter_.clear();
  45. for (auto layer_size_parameter : size_parameter)
  46. if (layer_size_parameter <= 0.0)
  47. throw std::invalid_argument("Size parameter should be positive!");
  48. else size_parameter_.push_back(layer_size_parameter);
  49. }
  50. // end of void MultiLayerMie::SetSizeParameter(...);
  51. // ********************************************************************** //
  52. // ********************************************************************** //
  53. // ********************************************************************** //
  54. void MultiLayerMie::SetIndex(std::vector< std::complex<double> > index) {
  55. index_.clear();
  56. for (auto value : index) index_.push_back(value);
  57. } // end of void MultiLayerMie::SetIndex(...);
  58. // ********************************************************************** //
  59. // ********************************************************************** //
  60. // ********************************************************************** //
  61. /// nMie starts layer numeration from 1 (no separation of target
  62. /// and coating). So the first elment (zero-indexed) is not used
  63. /// and has some unused value.
  64. /// Kostya, that's no longer the case. Now the layer numbering starts at zero.
  65. void MultiLayerMie::GenerateSizeParameter() {
  66. // size_parameter_.clear();
  67. // size_parameter_.push_back(0.0);
  68. // double radius = 0.0;
  69. // for (auto width : target_thickness_) {
  70. // radius += width;
  71. // size_parameter_.push_back(2*PI*radius / wavelength_);
  72. // }
  73. // for (auto width : coating_thickness_) {
  74. // radius += width;
  75. // size_parameter_.push_back(2*PI*radius / wavelength_);
  76. // }
  77. // total_radius_ = radius;
  78. } // end of void MultiLayerMie::GenerateSizeParameter();
  79. // ********************************************************************** //
  80. // ********************************************************************** //
  81. // ********************************************************************** //
  82. void MultiLayerMie::RunMie(double *Qext_out, double *Qsca_out,
  83. double *Qabs_out, double *Qbk_out) {
  84. if (size_parameter_.size() != index_.size())
  85. throw std::invalid_argument("Each size parameter should have only one index!");
  86. int L = static_cast<int>(size_parameter_.size()) - 1;
  87. double Qext, Qsca, Qabs, Qbk, Qpr, g, Albedo;
  88. int nt = 0;
  89. double *Theta = (double *)malloc(nt * sizeof(double));
  90. complex *S1 = (complex *)malloc(nt * sizeof(complex *));
  91. complex *S2 = (complex *)malloc(nt * sizeof(complex *));
  92. double *x = &(size_parameter_.front());
  93. complex *m = &(index_.front());
  94. int terms = 0;
  95. terms = nMie(L, x, m, nt, Theta,
  96. &Qext, &Qsca, &Qabs, &Qbk, &Qpr, &g, &Albedo,
  97. S1,S2);
  98. free(Theta);
  99. free(S1);
  100. free(S2);
  101. if (terms == 0) {
  102. *Qext_out = Qfaild_;
  103. *Qsca_out = Qfaild_;
  104. *Qabs_out = Qfaild_;
  105. *Qbk_out = Qfaild_;
  106. throw std::invalid_argument("Failed to evaluate Q!");
  107. }
  108. *Qext_out = Qext;
  109. *Qsca_out = Qsca;
  110. *Qabs_out = Qabs;
  111. *Qbk_out = Qbk;
  112. } // end of void MultiLayerMie::RunMie();
  113. // ********************************************************************** //
  114. // ********************************************************************** //
  115. // ********************************************************************** //
  116. double MultiLayerMie::GetTotalRadius() {
  117. if (total_radius_ == 0) GenerateSizeParameter();
  118. return total_radius_;
  119. } // end of double MultiLayerMie::GetTotalRadius();
  120. // ********************************************************************** //
  121. // ********************************************************************** //
  122. // ********************************************************************** //
  123. std::vector< std::vector<double> >
  124. MultiLayerMie::GetSpectra(double from_WL, double to_WL, int samples) {
  125. std::vector< std::vector<double> > spectra;
  126. double step_WL = (to_WL - from_WL)/ static_cast<double>(samples);
  127. double wavelength_backup = wavelength_;
  128. long fails = 0;
  129. for (double WL = from_WL; WL < to_WL; WL += step_WL) {
  130. double Qext, Qsca, Qabs, Qbk;
  131. wavelength_ = WL;
  132. try {
  133. RunMie(&Qext, &Qsca, &Qabs, &Qbk);
  134. } catch( const std::invalid_argument& ia ) {
  135. fails++;
  136. continue;
  137. }
  138. //printf("%3.1f ",WL);
  139. spectra.push_back({wavelength_, Qext, Qsca, Qabs, Qbk});
  140. } // end of for each WL in spectra
  141. printf("fails %li\n",fails);
  142. wavelength_ = wavelength_backup;
  143. return spectra;
  144. }
  145. // ********************************************************************** //
  146. // ********************************************************************** //
  147. // ********************************************************************** //
  148. ///MultiLayerMie::
  149. } // end of namespace nmie