00001 #ifndef CCTBX_ELTBX_XRAY_SCATTERING_H
00002 #define CCTBX_ELTBX_XRAY_SCATTERING_H
00003
00004 #include <cctbx/eltbx/basic.h>
00005 #include <cctbx/eltbx/xray_scattering/gaussian.h>
00006 #include <boost/optional.hpp>
00007 #include <boost/config.hpp>
00008 #include <stdexcept>
00009 #include <ctype.h>
00010
00011 namespace cctbx { namespace eltbx { namespace xray_scattering {
00012
00013 static const char *standard_labels[] = {
00014 "H", "D", "T",
00015 "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al",
00016 "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn",
00017 "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr",
00018 "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag",
00019 "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce",
00020 "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm",
00021 "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg",
00022 "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th", "Pa",
00023 "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf",
00024 "H1-", "D1-", "T1-",
00025 "Li1+", "Be2+", "Cval", "O1-", "O2-", "F1-", "Na1+", "Mg2+",
00026 "Al3+", "Sival", "Si4+", "Cl1-", "K1+", "Ca2+", "Sc3+", "Ti2+",
00027 "Ti3+", "Ti4+", "V2+", "V3+", "V5+", "Cr2+", "Cr3+", "Mn2+",
00028 "Mn3+", "Mn4+", "Fe2+", "Fe3+", "Co2+", "Co3+", "Ni2+", "Ni3+",
00029 "Cu1+", "Cu2+", "Zn2+", "Ga3+", "Ge4+", "Br1-", "Rb1+", "Sr2+",
00030 "Y3+", "Zr4+", "Nb3+", "Nb5+", "Mo3+", "Mo5+", "Mo6+", "Ru3+",
00031 "Ru4+", "Rh3+", "Rh4+", "Pd2+", "Pd4+", "Ag1+", "Ag2+", "Cd2+",
00032 "In3+", "Sn2+", "Sn4+", "Sb3+", "Sb5+", "I1-", "Cs1+", "Ba2+",
00033 "La3+", "Ce3+", "Ce4+", "Pr3+", "Pr4+", "Nd3+", "Pm3+", "Sm3+",
00034 "Eu2+", "Eu3+", "Gd3+", "Tb3+", "Dy3+", "Ho3+", "Er3+", "Tm3+",
00035 "Yb2+", "Yb3+", "Lu3+", "Hf4+", "Ta5+", "W6+", "Os4+", "Ir3+",
00036 "Ir4+", "Pt2+", "Pt4+", "Au1+", "Au3+", "Hg1+", "Hg2+", "Tl1+",
00037 "Tl3+", "Pb2+", "Pb4+", "Bi3+", "Bi5+", "Ra2+", "Ac3+", "Th4+",
00038 "U3+", "U4+", "U6+", "Np3+", "Np4+", "Np6+", "Pu3+", "Pu4+",
00039 "Pu6+", 0
00040 };
00041
00042 inline
00043 bool
00044 is_reserved_scattering_type_label(
00045 std::string const& label)
00046 {
00047 if (label == "const") return true;
00048 if (label == "unknown") return true;
00049 return false;
00050 }
00051
00052 inline
00053 void
00054 throw_if_reserved_scattering_type_label(
00055 std::string const& label)
00056 {
00057 if (is_reserved_scattering_type_label(label)) {
00058 throw std::runtime_error(
00059 "Reserved scattering type label: \""+label+"\"");
00060 }
00061 }
00062
00063 inline
00064 boost::optional<std::string>
00065 get_standard_label(
00066 std::string const& label,
00067 bool exact=false,
00068 bool optional=false)
00069 {
00070 if (label == "const") return boost::optional<std::string>(label);
00071 std::string work_label = basic::strip_label(label, exact);
00072 const char* result = 0;
00073 int m = 0;
00074 for (const char **std_lbl = standard_labels; *std_lbl; std_lbl++) {
00075 int i = basic::match_labels(work_label, *std_lbl);
00076 if (i < 0 ) {
00077 return boost::optional<std::string>(*std_lbl);
00078 }
00079 if (i > m && !isdigit((*std_lbl)[i-1])) {
00080 m = i;
00081 result = *std_lbl;
00082 }
00083 }
00084 if (exact || result == 0) {
00085 if (optional) return boost::optional<std::string>();
00086 throw std::runtime_error(
00087 "Unknown scattering type label: \"" + label + "\"");
00088 }
00089 return boost::optional<std::string>(result);
00090 }
00091
00092 inline
00093 std::string
00094 replace_hydrogen_isotype_labels(std::string standard_label)
00095 {
00096 if (standard_label == "D" || standard_label == "T" ) return "H";
00097 else if (standard_label == "D1-" || standard_label == "T1-") return "H1-";
00098 return standard_label;
00099 }
00100
00101 namespace detail {
00102
00103 static const float undefined = -99999.;
00104
00105 template <std::size_t N>
00106 struct raw_table_entry
00107 {
00108 const char* label;
00109 float a[N], b[N], c;
00110 };
00111
00112 }
00113
00115
00119 template <std::size_t N>
00120 class base
00121 {
00122 public:
00124 base() : table_(0), entry_(0) {}
00125
00127 base(const detail::raw_table_entry<N>* table_raw,
00128 const char* table,
00129 std::string const& label,
00130 bool exact);
00131
00133
00137 bool
00138 is_valid() const { return entry_->label != 0; }
00139
00141 const char* table() const { return table_; }
00142
00144 const char* label() const { return entry_->label; }
00145
00147 gaussian
00148 fetch() const
00149 {
00150 typedef af::small<double, gaussian::max_n_terms> small_t;
00151 return gaussian(
00152 small_t(entry_->a, entry_->a+N),
00153 small_t(entry_->b, entry_->b+N),
00154 entry_->c, true);
00155 }
00156
00157 protected:
00158 const char *table_;
00159 const detail::raw_table_entry<N>* entry_;
00160 void next_entry();
00161 };
00162
00163
00164 template <std::size_t N>
00165 base<N>::base(const detail::raw_table_entry<N>* table_raw,
00166 const char* table,
00167 std::string const& label,
00168 bool exact)
00169 :
00170 table_(table), entry_(0)
00171 {
00172 throw_if_reserved_scattering_type_label(label);
00173 std::string std_lbl = replace_hydrogen_isotype_labels(
00174 *get_standard_label(label, exact));
00175 for (const detail::raw_table_entry<N>* entry = table_raw;
00176 entry->label;
00177 entry++) {
00178 if (entry->label == std_lbl) {
00179 entry_ = entry;
00180 break;
00181 }
00182 }
00183 if (entry_ == 0) {
00184 throw std::runtime_error(
00185 "Unknown scattering type label: \"" + label + "\"");
00186 }
00187 }
00188
00189
00190 template <std::size_t N>
00191 void
00192 base<N>::next_entry()
00193 {
00194 if (is_valid()) entry_++;
00195 }
00196
00198
00228 class it1992: public base<4>
00229 {
00230 public:
00232 typedef base<4> base_type;
00233
00235 it1992() {}
00236
00238
00248 it1992(std::string const& label, bool exact=false);
00249
00250 protected:
00251 friend class it1992_iterator;
00252 };
00253
00257 class it1992_iterator
00258 {
00259 public:
00261 it1992_iterator();
00262
00264
00266 it1992
00267 next();
00268
00269 private:
00270 it1992 current_;
00271 };
00272
00274
00303 class wk1995: public base<5>
00304 {
00305 public:
00307 typedef base<5> base_type;
00308
00310 wk1995() {}
00311
00313
00323 wk1995(std::string const& label, bool exact=false);
00324
00325 protected:
00326 friend class wk1995_iterator;
00327 };
00328
00332 class wk1995_iterator
00333 {
00334 public:
00336 wk1995_iterator();
00337
00339
00341 wk1995
00342 next();
00343
00344 private:
00345 wk1995 current_;
00346 };
00347
00348 }}}
00349
00350 #endif // CCTBX_ELTBX_XRAY_SCATTERING_H