/** * \file FormFactorTable.h \brief A class for computation of * atomic form factors for SAXS calculations * * Copyright 2007-2010 IMP Inventors. All rights reserved. * */ #include #include #include #include #include #include #include IMPSAXS_BEGIN_NAMESPACE IntKey FormFactorTable::form_factor_type_key_ = IntKey("form factor key"); std::map FormFactorTable::element_ff_type_map_; Float FormFactorTable::zero_form_factors_[] = { -0.720147, 0.50824, 6.16294, 4.94998, 9.36656, 13.0855, // H C N O S P -0.720228, 6.993, 7.9864, 8.9805, 14.9965, 20.9946, 24.9936, 30.9825, 72.324, // He Ne Na Mg Ca Fe Zn Se Au -0.211907, -0.932054, -1.6522, 5.44279, 4.72265,4.0025,4.22983,3.50968,8.64641 // CH CH2 CH3 NH NH2 NH3 OH OH2 SH }; Float FormFactorTable::vacuum_zero_form_factors_[] = { 0.999953, 5.9992, 6.9946, 7.9994, 15.9998, 14.9993, // H C N O S P 0.999872, 9.999, 10.9924, 11.9865, 18.0025, 24.0006, 27.9996, 33.9885,78.9572, // He Ne Na Mg Ca Fe Zn Se Au 6.99915, 7.99911, 8.99906, 7.99455, 8.99451, 9.99446, 8.99935, 9.9993, 16.9998 // CH CH2 CH3 NH NH2 NH3 OH OH2 SH }; Float FormFactorTable::dummy_zero_form_factors_[] = { 1.7201, 5.49096, 0.83166, 3.04942, 6.63324, 1.91382, // H C N O S P 1.7201, 3.006, 3.006, 3.006, 3.006, 3.006, 3.006, 3.006, 6.63324, // He Ne Na Mg Ca Fe Zn Se Au 7.21106, 8.93116, 10.6513, 2.55176, 4.27186, 5.99196, 4.76952, 6.48962,8.35334 // CH CH2 CH3 NH NH2 NH3 OH OH2 SH }; // electron density of solvent - default=0.334 e/A^3 (H2O) Float FormFactorTable::rho_ = 0.334; std::istream & operator>>(std::istream & s, FormFactorTable::AtomFactorCoefficients & atom_factor_coefficients) { // read atom type s >> atom_factor_coefficients.atom_type_; // read ai values for (unsigned int i = 0; i < 5; i++) { s >> atom_factor_coefficients.a_[i]; } s >> atom_factor_coefficients.c_; // c value // read bi values for (unsigned int i = 0; i < 5; i++) { s >> atom_factor_coefficients.b_[i]; } return s >> atom_factor_coefficients.excl_vol_; // excluded volume } std::ostream & operator<<(std::ostream & s, const FormFactorTable::AtomFactorCoefficients & atom_factor_coefficients) { s << atom_factor_coefficients.atom_type_ << ' '; for (unsigned int i = 0; i < 5; i++) { s << atom_factor_coefficients.a_[i] << ' '; } s << atom_factor_coefficients.c_ << ' '; for (unsigned int i = 0; i < 5; i++) { s << atom_factor_coefficients.b_[i] << ' '; } return s << atom_factor_coefficients.excl_vol_ << std::endl; } FormFactorTable::FormFactorTable() { init_element_form_factor_map(); } FormFactorTable::FormFactorTable(const String& table_name, Float min_q, Float max_q, Float delta_q): min_q_(min_q), max_q_(max_q), delta_q_(delta_q) { init_element_form_factor_map(); // read form factor coefficients from file int ffnum = read_form_factor_table(table_name); if(ffnum > 0) { // form factors found in form factor file // init zero_form_factors so that they are computed from the file for(int i=0; i (HEAVY_ATOM_SIZE, form_factor_template); // compute all the form factors compute_form_factors_all_atoms(); compute_form_factors_heavy_atoms(); } } void FormFactorTable::init_element_form_factor_map() { element_ff_type_map_[atom::H] = H; element_ff_type_map_[atom::He] = He; element_ff_type_map_[atom::C] = C; element_ff_type_map_[atom::N] = N; element_ff_type_map_[atom::O] = O; element_ff_type_map_[atom::Ne] = Ne; element_ff_type_map_[atom::Na] = Na; element_ff_type_map_[atom::Mg] = Mg; element_ff_type_map_[atom::P] = P; element_ff_type_map_[atom::S] = S; element_ff_type_map_[atom::Ca] = Ca; element_ff_type_map_[atom::Fe] = Fe; element_ff_type_map_[atom::Zn] = Zn; element_ff_type_map_[atom::Se] = Se; element_ff_type_map_[atom::Au] = Au; } int FormFactorTable::read_form_factor_table(const String & table_name) { std::ifstream s(table_name.c_str()); if (!s) { IMP_THROW("Can't find form factor table file " << table_name, IOException); } atom::ElementTable e_table = atom::get_element_table(); // init coefficients table form_factors_coefficients_ = std::vector(ALL_ATOM_SIZE); // skip the comment lines char c; const int MAX_LENGTH = 1000; char line[MAX_LENGTH]; while (s.get(c)) { if (c == '#') { // if comment line, read the whole line and move on s.getline(line, MAX_LENGTH); } else { // return the first character s.putback(c); break; } } // read the data files AtomFactorCoefficients coeff; int counter = 0; while (s >> coeff) { // find FormFactorAtomType atom::Element e = e_table.get_element(coeff.atom_type_); FormFactorAtomType ff_type = get_form_factor_atom_type(e); if(ff_type != UNK) { form_factors_coefficients_[ff_type] = coeff; counter++; IMP_LOG(TERSE, "read_form_factor_table: Atom type found: " << coeff.atom_type_ << std::endl); } else { IMP_LOG(TERSE, "Atom type is not supported " << coeff.atom_type_ << std::endl); } } IMP_LOG(TERSE, counter << " form factors were read from file " << std::endl); return counter; } void FormFactorTable::show(std::ostream & out, std::string prefix) const { for (unsigned int i = 0; i < HEAVY_ATOM_SIZE; i++) { out << prefix << " FFATOMTYPE " << i << " zero_ff " << zero_form_factors_[i] << " vacuum_ff " << vacuum_zero_form_factors_[i] << " dummy_ff " << dummy_zero_form_factors_[i] << std::endl; } } /* f(q) = f_atomic(q) - f_solvent(q) f_atomic(q) = c + SUM [ a_i * EXP( - b_i * (q/4pi)^2 )] i=1,5 f_solvent(q) = rho * v_i * EXP( (- v_i^(2/3) / (4pi)) * q^2 ) */ void FormFactorTable::compute_form_factors_all_atoms() { unsigned int number_of_q_entries = algebra::get_rounded((max_q_ - min_q_) / delta_q_ ) + 1; static Float two_third = 2.0 / 3; static Float one_over_four_pi = 1 / 4*PI; Floats qq(number_of_q_entries), ss(number_of_q_entries); // store qq and ss for the faster calculation for (unsigned int iq=0; iq::const_iterator i = element_ff_type_map_.find(e); if(i != element_ff_type_map_.end()) return i->second; else return UNK; } Float FormFactorTable::get_form_factor(Particle *p, FormFactorType ff_type) const { // initialization by request if (p->has_attribute(form_factor_type_key_)) { return zero_form_factors_[p->get_value(form_factor_type_key_)]; } FormFactorAtomType ff_atom_type = get_form_factor_atom_type(p, ff_type); if(ff_atom_type >= HEAVY_ATOM_SIZE) { IMP_WARN( "Can't find form factor for particle " << atom::Atom(p).get_atom_type().get_string() << " using default" << std::endl); ff_atom_type = N; } Float form_factor = zero_form_factors_[ff_atom_type]; p->add_cache_attribute(form_factor_type_key_, ff_atom_type); return form_factor; } Float FormFactorTable::get_vacuum_form_factor(Particle *p, FormFactorType ff_type) const { if (p->has_attribute(form_factor_type_key_)) { return vacuum_zero_form_factors_[p->get_value(form_factor_type_key_)]; } FormFactorAtomType ff_atom_type = get_form_factor_atom_type(p, ff_type); if(ff_atom_type >= HEAVY_ATOM_SIZE) { IMP_WARN( "Can't find form factor for particle " << atom::Atom(p).get_atom_type().get_string() << " using default value of nitrogen" << std::endl); ff_atom_type = N; } Float form_factor = vacuum_zero_form_factors_[ff_atom_type]; p->add_attribute(form_factor_type_key_, ff_atom_type); return form_factor; } Float FormFactorTable::get_dummy_form_factor(Particle *p, FormFactorType ff_type) const { if (p->has_attribute(form_factor_type_key_)) { return dummy_zero_form_factors_[p->get_value(form_factor_type_key_)]; } FormFactorAtomType ff_atom_type = get_form_factor_atom_type(p, ff_type); if(ff_atom_type >= HEAVY_ATOM_SIZE) { IMP_WARN( "Can't find form factor for particle " << atom::Atom(p).get_atom_type().get_string() << " using default value of nitrogen" << std::endl); ff_atom_type = N; } Float form_factor = dummy_zero_form_factors_[ff_atom_type]; p->add_attribute(form_factor_type_key_, ff_atom_type); return form_factor; } Float FormFactorTable::get_radius(Particle* p, FormFactorType ff_type) const { // dummy_zero_form_factor = volume * rho // volume = 4/3 * pi * r^3 // r^3 = 3*dummy_zero_form_factor / 4*pi*rho static Float one_third = 1.0/3; static Float c = 3.0/(4*PI*rho_); Float form_factor = get_dummy_form_factor(p, ff_type); return std::pow(c*form_factor, one_third); } const Floats& FormFactorTable::get_form_factors(Particle *p, FormFactorType ff_type) const { // initialization by request // store the index of the form factors in the particle if (p->has_attribute(form_factor_type_key_)) return form_factors_[p->get_value(form_factor_type_key_)]; FormFactorAtomType ff_atom_type = get_form_factor_atom_type(p, ff_type); if(ff_atom_type >= HEAVY_ATOM_SIZE) { IMP_WARN( "Can't find form factor for particle " << atom::Atom(p).get_atom_type().get_string() << " using default value of nitrogen" << std::endl); ff_atom_type = N; } p->add_attribute(form_factor_type_key_, ff_atom_type); return form_factors_[ff_atom_type]; } FormFactorTable* default_form_factor_table() { static FormFactorTable ff; return &ff; } IMPSAXS_END_NAMESPACE