PDB.h
Go to the documentation of this file.
00001 // Copyright (c) 2009-2010  INRIA Sophia-Antipolis (France).
00002 // All rights reserved.
00003 //
00004 //This file is part of ESBTL.
00005 //
00006 //ESBTL is free software: you can redistribute it and/or modify
00007 //it under the terms of the GNU General Public License as published by
00008 //the Free Software Foundation, either version 3 of the License, or
00009 //(at your option) any later version.
00010 //
00011 //ESBTL is distributed in the hope that it will be useful,
00012 //but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //GNU General Public License for more details.
00015 //
00016 //You should have received a copy of the GNU General Public License
00017 //along with ESBTL.  If not, see <http://www.gnu.org/licenses/>.
00018 //
00019 //
00020 //Additional permission under GNU GPL version 3 section 7
00021 //
00022 //If you modify this Library, or any covered work, by linking or
00023 //combining it with CGAL (or a modified version of that library), the
00024 //licensors of this Library grant you additional permission to convey
00025 //the resulting work. Corresponding Source for a non-source form of
00026 //such a combination shall include the source code for the parts of CGAL
00027 //used as well as that of the covered work. 
00028 //
00029 //
00030 //
00031 // Author(s)     :  Sébastien Loriot
00032 
00033 
00034 
00035 
00036 #ifndef ESBTL_PDB_H
00037 #define ESBTL_PDB_H
00038 
00039 #include<boost/lexical_cast.hpp>
00040 #include <boost/algorithm/string.hpp>
00041 #include <boost/format.hpp>
00042 #include <sstream>
00043 #include <iostream>
00044 #include <typeinfo>
00045 #include <ESBTL/constants.h>
00046 
00047 
00048 
00049 #define RECOVER_FIELD(FNAME,TYPE,FROM,TO,DEF) \
00050   TYPE get_##FNAME(const std::string& line) const { \
00051     if (line.length() < TO){\
00052       if (! Mandatory_fields::FNAME) return TYPE(DEF);\
00053       else{\
00054           std::cerr << "Fatal error: Cannot extract field \'" << #FNAME << "\' in \n";\
00055           std::cerr << "<|" << line << "|>\n";\
00056           exit (EXIT_FAILURE);\
00057       }\
00058     }\
00059     return PDB::extract_field<TYPE>(line,FROM,TO,DEF,#FNAME,Mandatory_fields::FNAME); \
00060   }
00061   
00062 
00063 namespace ESBTL{
00064   namespace PDB{
00066   enum Record_type{ATOM=0,HETATM,MODEL,ENDMDL,TER,END,ANISOU,CONECT,MASTER,UNKNOWN};
00067   
00069   template<class T>
00070   T extract_field(const std::string& line,unsigned from, unsigned to,T default_value,const char* name,bool is_mandatory=false){
00071     std::string s=line.substr(from,to-from+1);
00072     boost::trim(s);
00073     if (s.length()==0){
00074       if (!is_mandatory)
00075         return default_value;
00076       else{
00077         std::cerr << "Fatal error: field \'"<< name << "\' is empty in \n";
00078         std::cerr  << "<|" << line << "|>\n";
00079         exit (EXIT_FAILURE);
00080       }
00081     }
00082       try{
00083         return boost::lexical_cast<T>(s);
00084       }
00085       catch(boost::bad_lexical_cast &)
00086       {
00087         std::cerr << "Fatal error: Cannot convert \'"<< s << "\' to " << typeid(T).name() << " in line\n";
00088         std::cerr  << "<|" << line << "|>\n";
00089         exit (EXIT_FAILURE);
00090       }
00091   }
00095   struct Mandatory_fields_default{
00096     static const bool record_name=true;
00097     static const bool atom_serial_number=true;
00098     static const bool atom_name=true;
00099     static const bool alternate_location=false;
00100     static const bool residue_name=true;
00101     static const bool chain_identifier=false;
00102     static const bool residue_sequence_number=true;
00103     static const bool insertion_code=false;
00104     static const bool x=true;
00105     static const bool y=true;
00106     static const bool z=true;
00107     static const bool occupancy=true;
00108     static const bool temperature_factor=true;
00109     static const bool element=true;
00110     static const bool charge_str=false;
00111     static const bool model_number=true;
00112   };
00113  
00118   //TODO put the string line inside ?
00119   template <class Mandatory_fields=Mandatory_fields_default>
00120   class Line_format{
00121   private:  
00122     PDB::Record_type type;
00123 
00124   public:
00125     //Easy to do with a MACRO
00129     Line_format(const std::string& line){
00130       type=PDB::UNKNOWN;
00131       if (strncmp(line.c_str(),"ATOM",4)==0)    type=PDB::ATOM;
00132       if (strncmp(line.c_str(),"HETATM",6)==0)  type=PDB::HETATM;
00133       if (strncmp(line.c_str(),"MODEL",5)==0)   type=PDB::MODEL;
00134       if (strncmp(line.c_str(),"ENDMDL",6)==0)  type=PDB::ENDMDL;
00135       if (strncmp(line.c_str(),"TER",3)==0)     type=PDB::TER;
00136       if (strncmp(line.c_str(),"END",3)==0)     type=PDB::END;
00137       if (strncmp(line.c_str(),"ANISOU",6)==0)  type=PDB::ANISOU;
00138       if (strncmp(line.c_str(),"CONECT",6)==0)  type=PDB::CONECT;
00139       if (strncmp(line.c_str(),"MASTER",6)==0)  type=PDB::MASTER;
00140     }
00141     
00143     bool is_hetatm() const {return (type==PDB::HETATM);}
00144     
00145     //ATOM and HETATM fields
00146     RECOVER_FIELD(record_name,std::string,0,5," ")
00147     RECOVER_FIELD(atom_serial_number,int,6,10,-1)
00148     RECOVER_FIELD(atom_name,std::string,12,15," ")
00149     RECOVER_FIELD(alternate_location,char,16,16,' ')
00150     RECOVER_FIELD(residue_name,std::string,17,19," ")
00151     RECOVER_FIELD(chain_identifier,char,21,21,' ')
00152     RECOVER_FIELD(residue_sequence_number,int,22,25,-1)
00153     RECOVER_FIELD(insertion_code,char,26,26,' ')
00154     RECOVER_FIELD(x,double,30,37,NO_FLOAT)
00155     RECOVER_FIELD(y,double,38,45,NO_FLOAT)
00156     RECOVER_FIELD(z,double,46,53,NO_FLOAT)
00157     RECOVER_FIELD(occupancy,double,54,59,NO_FLOAT)
00158     RECOVER_FIELD(temperature_factor,double,60,65,NO_FLOAT)
00159     RECOVER_FIELD(element,std::string,76,77," ")
00161     RECOVER_FIELD(charge_str,std::string,78,79," ")
00162     
00165     int get_charge(const std::string& line) const {
00166       std::string charge_str=get_charge_str(line);
00167       if (charge_str==" ")
00168         return NO_CHARGE;
00169       else{
00170         int ch=1;
00171         if (charge_str.size()==2){
00172           if (charge_str[1]=='-') ch*=-1;
00173           else{
00174             if (charge_str[1]!='+'){
00175               if (! Mandatory_fields::charge_str) return 99;
00176               std::cerr << "Fatal error: Cannot extract field \'charge\' in \n";
00177               std::cerr << "<|" << line << "|>\n";\
00178               exit(EXIT_FAILURE);
00179             }
00180           }
00181         }
00182         try{
00183           return ch*boost::lexical_cast<int>(charge_str[0]);
00184         }
00185         catch(boost::bad_lexical_cast &){
00186           if (! Mandatory_fields::charge_str) return 99;
00187           std::cerr << "Fatal error: Cannot convert \'"<< charge_str[0] << "\' to " << typeid(int).name() << " in line\n";
00188           std::cerr  << "<|" << line << "|>\n";
00189           exit (EXIT_FAILURE);          
00190         }
00191       }
00192     }
00193     
00194     //~ //element from atom name
00195     //~ RECOVER_FIELD(element_using_atom_name,std::string,12,13," ")
00196     
00197     //MODEL fields
00198     RECOVER_FIELD(model_number,int,10,13,-1)
00199     
00200     
00201     PDB::Record_type record_type() const{
00202       return type;
00203     }
00204     
00205   };  
00206   
00207 
00208   template<class PDB_Atom>
00209   std::string 
00210   get_atom_pdb_format(const PDB_Atom& atom)
00211   {
00212     std::stringstream buf(std::stringstream::out);
00213     buf << ( !atom.is_hetatm() ? "ATOM  ":"HETATM" );
00214     buf <<  boost::format("%5d %4s%c%3s %c%4d%c   %8.3f%8.3f%8.3f%6.2f%6.2f          %2s")
00215             % atom.atom_serial_number()
00216             % atom.atom_name().c_str()
00217             % atom.alternate_location()
00218             % atom.residue_name().c_str()
00219             % atom.chain_identifier()
00220             % atom.residue_sequence_number()
00221             % atom.insertion_code()
00222             % atom.x()
00223             % atom.y()
00224             % atom.z()
00225             % atom.occupancy()
00226             % atom.temperature_factor()
00227             % atom.element().c_str();
00228     if (atom.charge()==NO_CHARGE)   buf << "  ";
00229     else buf << boost::format("% 2i") % atom.charge();
00230     return buf.str();
00231   }
00232 
00233   template<class PDB_Atom>
00234   std::string 
00235   get_atom_pdb_reduced_format(const PDB_Atom& atom)
00236   {
00237     std::stringstream buf(std::stringstream::out);
00238     buf <<  boost::format("%5d %4s%c%3s %c%4d%c")
00239             % atom.atom_serial_number()
00240             % atom.atom_name().c_str()
00241             % atom.alternate_location()
00242             % atom.residue_name().c_str()
00243             % atom.chain_identifier()
00244             % atom.residue_sequence_number()
00245             % atom.insertion_code();
00246     return buf.str();
00247   }
00248   
00249 } //namespace PDB
00250 
00251 //global access functions
00252   template <class Mandatory_fields>
00253   bool get_is_hetatm(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.is_hetatm(p.second);}
00254   template <class Mandatory_fields>
00255   int get_atom_serial_number(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_atom_serial_number(p.second) ;}
00256   template <class Mandatory_fields>
00257   std::string get_atom_name(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_atom_name(p.second) ;}
00258   template <class Mandatory_fields>
00259   char get_alternate_location(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_alternate_location(p.second) ;}
00260   template <class Mandatory_fields>
00261   double get_occupancy(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_occupancy(p.second) ;}
00262   template <class Mandatory_fields>
00263   double get_temperature_factor(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_temperature_factor(p.second) ;}
00264   template <class Mandatory_fields>
00265   std::string get_element(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_element(p.second) ;}
00266   template <class Mandatory_fields>
00267   int get_charge(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_charge(p.second) ;}
00268   template <class Mandatory_fields>
00269   char get_chain_identifier(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_chain_identifier(p.second) ;}
00270   template <class Mandatory_fields>
00271   std::string get_residue_name(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_residue_name(p.second) ;}
00272   template <class Mandatory_fields>
00273   int get_residue_sequence_number(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_residue_sequence_number(p.second) ;}
00274   template <class Mandatory_fields>
00275   char get_insertion_code(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_insertion_code(p.second) ;}
00276   template <class Mandatory_fields>
00277   char get_x(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_x(p.second) ;}
00278   template <class Mandatory_fields>
00279   char get_y(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_y(p.second) ;}
00280   template <class Mandatory_fields>
00281   char get_z(const std::pair<PDB::Line_format<Mandatory_fields>,std::string>& p) {return p.first.get_z(p.second) ;}
00282 } //namespace ESBTL
00283 
00284 #endif //ESBTL_PDB_H