/** * \file FormFactorTable.h \brief A class for computation of * atomic and residue level 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_; std::map FormFactorTable::residue_type_form_factor_map_; Float FormFactorTable::zero_form_factors_[] = { -0.720147, -0.720228, // H He 1.591, 2.591, 3.591, 0.50824, 6.16294, 4.94998, 7.591, 6.993, // Li Be B C N O F Ne 7.9864, 8.9805, 9.984, 10.984, 13.0855, 9.36656, 13.984, 16.591, // Na Mg Al Si P S Cl Ar 15.984, 14.9965, 20.984, 21.984, 20.9946, 23.984, // K Ca2+ Cr Mn Fe2+ Co 24.984, 25.984, 24.9936, 30.9825, 31.984, 49.16, 70.35676, 71.35676, 72.324, // Ni Cu Zn2+ Se Br I Ir Pt 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, 0.999872, 2.99, 3.99, 4.99, 5.9992, 6.9946, 7.9994, 8.99, 9.999, // H He Li Be B C N O F Ne 10.9924, 11.9865, 12.99, 13.99, 14.9993, 15.9998, 16.99, 17.99, // Na Mg Al Si P S Cl Ar 18.99, 18.0025, 23.99, 24.99, 24.0006, 26.99, // K Ca2+ Cr Mn Fe2+ Co 27.99, 28.99, 27.9996, 33.99, 34.99, 52.99, 76.99, 77.99, 78.9572, // Ni Cu Zn2+ Se Br I Ir Pt 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, 1.7201, 1.399, 1.399, 1.399 , 5.49096, 0.83166, 3.04942, 1.399, 3.006, // H He Li? Be? B? C N O F? Ne 3.006, 3.006, 3.006, 3.006, 1.91382, 6.63324, 3.006, 1.399, // Na Mg Al? Si? P S Cl? Ar? 3.006, 3.006, 3.006, 3.006, 3.006, 3.006, // K? Ca2+ Cr? Mn? Fe2+ Co? 3.006, 3.006, 3.006, 3.006, 3.006, 3.83, 6.63324, 6.63324, 6.63324, // Ni? Cu? Zn2+ Se Br? I? Ir? Pt? 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(); init_residue_type_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(); init_residue_type_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::Li] = Li; element_ff_type_map_[atom::Be] = Be; element_ff_type_map_[atom::B] = B; 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::F] = F; 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::Al] = Al; element_ff_type_map_[atom::Si] = Si; element_ff_type_map_[atom::P] = P; element_ff_type_map_[atom::S] = S; element_ff_type_map_[atom::Cl] = Cl; element_ff_type_map_[atom::Ar] = Ar; element_ff_type_map_[atom::K] = K; element_ff_type_map_[atom::Ca] = Ca; element_ff_type_map_[atom::Cr] = Cr; element_ff_type_map_[atom::Mn] = Mn; element_ff_type_map_[atom::Fe] = Fe; element_ff_type_map_[atom::Co] = Co; element_ff_type_map_[atom::Ni] = Ni; element_ff_type_map_[atom::Cu] = Cu; element_ff_type_map_[atom::Zn] = Zn; element_ff_type_map_[atom::Se] = Se; element_ff_type_map_[atom::Br] = Br; element_ff_type_map_[atom::I] = I; element_ff_type_map_[atom::Ir] = Ir; element_ff_type_map_[atom::Pt] = Pt; element_ff_type_map_[atom::Au] = Au; } void FormFactorTable::init_residue_type_form_factor_map() { residue_type_form_factor_map_[atom::ALA] = FormFactor(9.037, 37.991, 28.954); residue_type_form_factor_map_[atom::ARG] = FormFactor(23.289, 84.972, 61.683); residue_type_form_factor_map_[atom::ASP] = FormFactor(20.165, 58.989, 38.824); residue_type_form_factor_map_[atom::ASN] = FormFactor(19.938, 59.985, 40.047); residue_type_form_factor_map_[atom::CYS] = FormFactor(18.403, 53.991, 35.588); residue_type_form_factor_map_[atom::GLN] = FormFactor(19.006, 67.984, 48.978); residue_type_form_factor_map_[atom::GLU] = FormFactor(19.233, 66.989, 47.755); residue_type_form_factor_map_[atom::GLY] = FormFactor(10.689, 28.992, 18.303); residue_type_form_factor_map_[atom::HIS] = FormFactor(21.235, 78.977, 57.742); residue_type_form_factor_map_[atom::ILE] = FormFactor(6.241, 61.989, 55.748); residue_type_form_factor_map_[atom::LEU] = FormFactor(6.241, 61.989, 55.748); residue_type_form_factor_map_[atom::LYS] = FormFactor(10.963, 70.983, 60.020); residue_type_form_factor_map_[atom::MET] = FormFactor(16.539, 69.989, 53.450); residue_type_form_factor_map_[atom::PHE] = FormFactor(9.206, 77.986, 68.7806); residue_type_form_factor_map_[atom::PRO] = FormFactor(8.613, 51.9897, 43.377); residue_type_form_factor_map_[atom::SER] = FormFactor(13.987, 45.991, 32.004); residue_type_form_factor_map_[atom::THR] = FormFactor(13.055, 53.99, 40.935); residue_type_form_factor_map_[atom::TYR] = FormFactor(14.156, 85.986, 71.83); residue_type_form_factor_map_[atom::TRP] = FormFactor(14.945, 98.979, 84.034); residue_type_form_factor_map_[atom::VAL] = FormFactor(7.173, 53.9896, 46.817); residue_type_form_factor_map_[atom::UNK] = FormFactor(9.037, 37.991, 28.954); } 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(atom::ResidueType rt) const { std::map::const_iterator i = residue_type_form_factor_map_.find(rt); if(i != residue_type_form_factor_map_.end()) return i->second.ff_; else { IMP_WARN("Can't find form factor for residue " << rt.get_string() << " using default value of ALA " << std::endl); return residue_type_form_factor_map_.find(atom::UNK)->second.ff_; } } float FormFactorTable::get_vacuum_form_factor(atom::ResidueType rt) const { std::map::const_iterator i = residue_type_form_factor_map_.find(rt); if(i != residue_type_form_factor_map_.end()) return i->second.vacuum_ff_; else { IMP_WARN("Can't find form factor for residue " << rt.get_string() << " using default value of ALA " << std::endl); return residue_type_form_factor_map_.find(atom::UNK)->second.vacuum_ff_; } } float FormFactorTable::get_dummy_form_factor(atom::ResidueType rt) const { std::map::const_iterator i = residue_type_form_factor_map_.find(rt); if(i != residue_type_form_factor_map_.end()) return i->second.dummy_ff_; else { IMP_WARN("Can't find form factor for residue " << rt.get_string() << " using default value of ALA " << std::endl); return residue_type_form_factor_map_.find(atom::UNK)->second.dummy_ff_; } } Float FormFactorTable::get_form_factor(Particle *p, FormFactorType ff_type) const { if(ff_type == CA_ATOMS) { // residue level form factors atom::ResidueType residue_type = atom::get_residue(atom::Atom(p)).get_residue_type(); return get_form_factor(residue_type); } // atomic form factor, 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(ff_type == CA_ATOMS) { // residue level form factors atom::ResidueType residue_type = atom::get_residue(atom::Atom(p)).get_residue_type(); return get_vacuum_form_factor(residue_type); } 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(ff_type == CA_ATOMS) { // residue level form factors atom::ResidueType residue_type = atom::get_residue(atom::Atom(p)).get_residue_type(); return get_dummy_form_factor(residue_type); } 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