diff --git a/modules/geom/src/composite3_op.cc b/modules/geom/src/composite3_op.cc index 87f799d516ab3be540ee287dbb2ceed98fee6d4a..09fb2c72e7430c2fc938534ff4167052485a4b24 100644 --- a/modules/geom/src/composite3_op.cc +++ b/modules/geom/src/composite3_op.cc @@ -178,76 +178,5 @@ bool IsInSphere(const Sphere& s, const Vec3& v){ return Length(s.GetOrigin()-v)<=s.GetRadius(); } -Line3 Vec3List::FitCylinder(const Vec3 initial_direction, const Vec3 center){ - //This function fits a cylinder to the positions in Vec3List - //It takes as argument an initial guess for the direction and the geometric - //center of the atoms. The center is not changed during optimisation as the - //best fitting cylinder can be shown to have its axis pass through the geometric center - Line3 axis=Line3(center,center+initial_direction), axis_old; - Real radius,res_sum_old,res_sum,delta_0=0.01,prec=0.0000001,err,norm,delta; - unsigned long n_step=1000, n_res=this->size(); - Vec3 v,gradient; - - radius=0.0; - delta=delta_0; - for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { - radius+=geom::Distance(axis,(*i)); - } - radius/=Real(n_res); - res_sum=0.0; - for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { - res_sum+=pow(Distance(axis,(*i))-radius,2.); - } - unsigned long k=0; - err=2.0*prec; - while (err>prec and k<n_step) { - res_sum_old=res_sum; - axis_old=axis; - radius=0.0; - if (k>50) { - delta=delta_0*pow((50./k),2.0); - } - for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { - radius+=Distance(axis,(*i)); - } - radius/=Real(n_res); - for (int j=0; j!=3; ++j){ - res_sum=0.0; - v=Vec3(0.0,0.0,0.0); - v[j]=delta; - axis=Line3(axis_old.GetOrigin(),axis_old.GetOrigin()+axis_old.GetDirection()+v); - radius=0.0; - for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { - radius+=Distance(axis,(*i)); - } - radius/=Real(n_res); - for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { - res_sum+=pow(Distance(axis,(*i))-radius,2.); - } - gradient[j]=(res_sum-res_sum_old)/delta; - } - norm=Dot(gradient,gradient); - if (norm>1.) { - gradient=Normalize(gradient); - } - axis=Line3(axis_old.GetOrigin(),axis_old.GetOrigin()+axis_old.GetDirection()-delta*gradient); - radius=0.0; - for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { - radius+=Distance(axis,(*i)); - } - radius/=Real(n_res); - res_sum=0.0; - for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { - res_sum+=pow(Distance(axis,(*i))-radius,2.); - } - err=fabs((res_sum-res_sum_old)/float(n_res)); - k++; - } - if (err>prec) { - std::cout<<"axis fitting did not converge"<<std::endl; - } - return axis; -} - } // ns diff --git a/modules/geom/src/vec3.cc b/modules/geom/src/vec3.cc index ea07f3cca30b46f4aeef0139d7f4a0a0aab9345b..6e657081fb7ed1496d85514b29f390aa52d6028e 100644 --- a/modules/geom/src/vec3.cc +++ b/modules/geom/src/vec3.cc @@ -19,8 +19,12 @@ #include <algorithm> #include <Eigen/SVD> -#include "vec3.hh" +#include "vec3.hh" +// TODO: these are for the (misplaced) Vec3List algorithm functions +#include "vecmat3_op.hh" +#include "composite3.hh" +#include "composite3_op.hh" namespace geom { @@ -68,18 +72,86 @@ Vec3 Vec3List::GetCenter() const return center/=this->size(); } -Line3 Vec3List::GetODRLine() +Line3 Vec3List::GetODRLine() const { Vec3 center=this->GetCenter(); Vec3 direction=this->GetPrincipalAxes().GetRow(2); return Line3(center,center+direction); } -Plane Vec3List::GetODRPlane() +Plane Vec3List::GetODRPlane() const { Vec3 origin=this->GetCenter(); Vec3 normal=this->GetPrincipalAxes().GetRow(0); return Plane(origin,normal); } +Line3 Vec3List::FitCylinder(const Vec3& initial_direction, const Vec3& center) const +{ + Line3 axis=Line3(center,center+initial_direction), axis_old; + Real radius,res_sum_old,res_sum,delta_0=0.01,prec=0.0000001,err,norm,delta; + unsigned long n_step=1000, n_res=this->size(); + Vec3 v,gradient; + + radius=0.0; + delta=delta_0; + for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { + radius+=geom::Distance(axis,(*i)); + } + radius/=Real(n_res); + res_sum=0.0; + for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { + res_sum+=pow(Distance(axis,(*i))-radius,2.); + } + unsigned long k=0; + err=2.0*prec; + while (err>prec and k<n_step) { + res_sum_old=res_sum; + axis_old=axis; + radius=0.0; + if (k>50) { + delta=delta_0*pow((50./k),2.0); + } + for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { + radius+=Distance(axis,(*i)); + } + radius/=Real(n_res); + for (int j=0; j!=3; ++j){ + res_sum=0.0; + v=Vec3(0.0,0.0,0.0); + v[j]=delta; + axis=Line3(axis_old.GetOrigin(),axis_old.GetOrigin()+axis_old.GetDirection()+v); + radius=0.0; + for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { + radius+=Distance(axis,(*i)); + } + radius/=Real(n_res); + for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { + res_sum+=pow(Distance(axis,(*i))-radius,2.); + } + gradient[j]=(res_sum-res_sum_old)/delta; + } + norm=Dot(gradient,gradient); + if (norm>1.) { + gradient=Normalize(gradient); + } + axis=Line3(axis_old.GetOrigin(),axis_old.GetOrigin()+axis_old.GetDirection()-delta*gradient); + radius=0.0; + for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { + radius+=Distance(axis,(*i)); + } + radius/=Real(n_res); + res_sum=0.0; + for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) { + res_sum+=pow(Distance(axis,(*i))-radius,2.); + } + err=fabs((res_sum-res_sum_old)/float(n_res)); + k++; + } + if (err>prec) { + std::cout<<"axis fitting did not converge"<<std::endl; + } + return axis; +} + } diff --git a/modules/geom/src/vec3.hh b/modules/geom/src/vec3.hh index ac3458837fc20245ac7d185a56a58cbf69b8eb08..7b4bb5b33fd33cccfe285f6d602bfa8d968bb687 100644 --- a/modules/geom/src/vec3.hh +++ b/modules/geom/src/vec3.hh @@ -189,15 +189,13 @@ inline std::ostream& operator<<(std::ostream& os, const Vec3& v) os << "[" << v.x << ", " << v.y << ", " << v.z << "]"; return os; } -} - -#include <ost/geom/vec2.hh> -#include <ost/geom/vec4.hh> -#include <ost/geom/mat3.hh> -#include <ost/geom/composite3.hh> +} // ns geom namespace geom { + // TODO: move to separate file + class Mat3; + class DLLEXPORT_OST_GEOM Vec3List : public std::vector<Vec3> { public: typedef std::vector<Vec3> base_type; @@ -213,30 +211,40 @@ public: base_type::operator=(rhs); return *this; } + + // TODO: move some or all of these to stand-alone functions Mat3 GetInertia() const; - Vec3 GetCenter() const; - Mat3 GetPrincipalAxes() const; - Line3 GetODRLine(); - Plane GetODRPlane(); - Line3 FitCylinder(const Vec3 initial_direction, const Vec3 center); - + Line3 GetODRLine() const; + Plane GetODRPlane() const; + + //This function fits a cylinder to the positions in Vec3List + //It takes as argument an initial guess for the direction and the geometric + //center of the atoms. The center is not changed during optimisation as the + //best fitting cylinder can be shown to have its axis pass through the geometric center + Line3 FitCylinder(const Vec3& initial_direction, const Vec3& center) const; }; +} // ns geom -inline Vec3::Vec3(const Vec2& v): x(v.x), y(v.y), z(0.0) { } +#include <ost/geom/vec2.hh> +#include <ost/geom/vec4.hh> +#include <ost/geom/mat3.hh> +#include <ost/geom/composite3.hh> -inline Vec3::Vec3(const Vec4& v): x(v.x), y(v.y), z(v.z) -{ - if (std::fabs(v.w)<1e-10) { - throw DivideByZeroException(); - } - x/=v.w; - y/=v.w; - z/=v.w; -} +namespace geom { + inline Vec3::Vec3(const Vec2& v): x(v.x), y(v.y), z(0.0) { } + inline Vec3::Vec3(const Vec4& v): x(v.x), y(v.y), z(v.z) + { + if (std::fabs(v.w)<1e-10) { + throw DivideByZeroException(); + } + x/=v.w; + y/=v.w; + z/=v.w; + } } // namespace geom diff --git a/modules/io/src/mol/dcd_io.cc b/modules/io/src/mol/dcd_io.cc index 15a290279063e9c2dd7dc9948f55c0d0d70437e6..5acc5bf4b79dcb0eca650ebe306f6d944cc78b68 100644 --- a/modules/io/src/mol/dcd_io.cc +++ b/modules/io/src/mol/dcd_io.cc @@ -67,7 +67,7 @@ bool less_index(const mol::AtomHandle& a1, const mol::AtomHandle& a2) } bool read_dcd_header(std::istream& istream, DCDHeader& header, bool& swap_flag, - bool& skip_flag, bool& gap_flag) + bool& ucell_flag, bool& gap_flag) { if (!istream) { return false; @@ -75,7 +75,7 @@ bool read_dcd_header(std::istream& istream, DCDHeader& header, bool& swap_flag, char dummy[4]; gap_flag=true; swap_flag=false; - skip_flag=false; + ucell_flag=false; if(gap_flag) istream.read(dummy,sizeof(dummy)); istream.read(header.hdrr,sizeof(char)*4); istream.read(reinterpret_cast<char*>(header.icntrl),sizeof(int)*20); @@ -91,8 +91,8 @@ bool read_dcd_header(std::istream& istream, DCDHeader& header, bool& swap_flag, } if(header.icntrl[19]!=0) { // CHARMM format - skip_flag=(header.icntrl[10]!=0); - if(skip_flag) { + ucell_flag=(header.icntrl[10]!=0); + if(ucell_flag) { LOG_VERBOSE("LoadCHARMMTraj: using CHARMM format with per-frame header"); } else { LOG_VERBOSE("LoadCHARMMTraj: using CHARMM format"); @@ -128,10 +128,10 @@ bool read_dcd_header(std::istream& istream, DCDHeader& header, bool& swap_flag, } -size_t calc_frame_size(bool skip_flag, bool gap_flag, size_t num_atoms) +size_t calc_frame_size(bool ucell_flag, bool gap_flag, size_t num_atoms) { size_t frame_size=0; - if (skip_flag) { + if (ucell_flag) { frame_size+=14*sizeof(int); } if (gap_flag) { @@ -143,33 +143,12 @@ size_t calc_frame_size(bool skip_flag, bool gap_flag, size_t num_atoms) bool read_frame(std::istream& istream, const DCDHeader& header, - size_t frame_size, bool skip_flag, bool gap_flag, + size_t frame_size, bool ucell_flag, bool gap_flag, bool swap_flag, std::vector<float>& xlist, std::vector<geom::Vec3>& frame, uint frame_num,geom::Vec3& cell_size,geom::Vec3& cell_angles) { char dummy[4]; - //if(skip_flag) istream.seekg(14*4,std::ios_base::cur); - if(skip_flag){ - istream.read(dummy,sizeof(dummy)); - double x,y,z,a,b,c; - istream.read(reinterpret_cast<char*>(&x),sizeof(double)); - istream.read(reinterpret_cast<char*>(&a),sizeof(double)); - istream.read(reinterpret_cast<char*>(&y),sizeof(double)); - istream.read(reinterpret_cast<char*>(&b),sizeof(double)); - istream.read(reinterpret_cast<char*>(&c),sizeof(double)); - istream.read(reinterpret_cast<char*>(&z),sizeof(double)); - istream.read(dummy,sizeof(dummy)); - cell_size[0]=x; - cell_size[1]=y; - cell_size[2]=z; - cell_angles[0]=acos(a); - cell_angles[1]=acos(b); - cell_angles[2]=acos(c); - if(a!=0.0||b!=0.0||c!=0.0){ - LOG_ERROR("LoadCHARMMTraj: periodic cell not parallelepipedic, cell angles might be wrong, handle carefully") - } - } // read each frame if(!istream) { @@ -178,6 +157,21 @@ bool read_frame(std::istream& istream, const DCDHeader& header, << frame_num << "Nothing left to be read"); return false; } + + if(ucell_flag){ + istream.read(dummy,sizeof(dummy)); + double tmp[6]; + istream.read(reinterpret_cast<char*>(tmp),sizeof(double)*6); + // a,alpha,b,beta,gamma,c (don't ask) + cell_size[0]=static_cast<Real>(tmp[0]); + cell_size[1]=static_cast<Real>(tmp[2]); + cell_size[2]=static_cast<Real>(tmp[5]); + cell_angles[0]=static_cast<Real>(acos(tmp[1])); + cell_angles[1]=static_cast<Real>(acos(tmp[3])); + cell_angles[2]=static_cast<Real>(acos(tmp[4])); + istream.read(dummy,sizeof(dummy)); + } + // x coord if(gap_flag) istream.read(dummy,sizeof(dummy)); istream.read(reinterpret_cast<char*>(&xlist[0]),sizeof(float)*xlist.size()); @@ -224,12 +218,12 @@ bool read_frame(std::istream& istream, const DCDHeader& header, } bool read_frame(std::istream& istream, const DCDHeader& header, - size_t frame_size, bool skip_flag, bool gap_flag, + size_t frame_size, bool ucell_flag, bool gap_flag, bool swap_flag, std::vector<float>& xlist, std::vector<geom::Vec3>& frame,uint frame_num) { geom::Vec3 cell_size=geom::Vec3(),cell_angles=geom::Vec3(); - return read_frame(istream,header, frame_size,skip_flag, gap_flag, + return read_frame(istream,header, frame_size,ucell_flag, gap_flag, swap_flag, xlist,frame,frame_num, cell_size, cell_angles); } @@ -247,8 +241,8 @@ mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist, // this atom li Profile profile_load("LoadCHARMMTraj"); DCDHeader header; - bool swap_flag=false, skip_flag=false, gap_flag=false; - read_dcd_header(istream, header, swap_flag, skip_flag, gap_flag); + bool swap_flag=false, ucell_flag=false, gap_flag=false; + read_dcd_header(istream, header, swap_flag, ucell_flag, gap_flag); if(alist.size() != static_cast<size_t>(header.t_atom_count)) { LOG_ERROR("LoadCHARMMTraj: atom count missmatch: " << alist.size() << " in coordinate file, " << header.t_atom_count @@ -260,18 +254,18 @@ mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist, // this atom li std::vector<geom::Vec3> clist(header.t_atom_count); std::vector<float> xlist(header.t_atom_count); geom::Vec3 cell_size, cell_angles; - size_t frame_size=calc_frame_size(skip_flag, gap_flag, xlist.size()); + size_t frame_size=calc_frame_size(ucell_flag, gap_flag, xlist.size()); int i=0; for(;i<header.num;i+=stride) { - std::cout << i << " " << header.num << std::endl; - if (!read_frame(istream, header, frame_size, skip_flag, gap_flag, + if (!read_frame(istream, header, frame_size, ucell_flag, gap_flag, swap_flag, xlist, clist, i,cell_size,cell_angles)) { break; } - if(skip_flag) { + if(ucell_flag) { cg.AddFrame(clist,cell_size,cell_angles); + } else { + cg.AddFrame(clist); } - else cg.AddFrame(clist); // skip frames (defined by stride) if(stride>1) istream.seekg(frame_size*(stride-1),std::ios_base::cur); @@ -321,7 +315,7 @@ private: void FetchFrame(uint frame); String filename_; DCDHeader header_; - bool skip_flag_; + bool ucell_flag_; bool swap_flag_; bool gap_flag_; std::ifstream stream_; @@ -337,17 +331,17 @@ private: void DCDCoordSource::FetchFrame(uint frame) { if (!loaded_) { - read_dcd_header(stream_, header_, swap_flag_, skip_flag_, gap_flag_); + read_dcd_header(stream_, header_, swap_flag_, ucell_flag_, gap_flag_); frame_start_=stream_.tellg(); loaded_=true; frame_count_=header_.num/stride_; } - size_t frame_size=calc_frame_size(skip_flag_, gap_flag_, + size_t frame_size=calc_frame_size(ucell_flag_, gap_flag_, header_.t_atom_count); size_t pos=frame_start_+frame_size*frame*stride_; stream_.seekg(pos,std::ios_base::beg); std::vector<float> xlist(header_.t_atom_count); - if (!read_frame(stream_, header_, frame_size, skip_flag_, gap_flag_, + if (!read_frame(stream_, header_, frame_size, ucell_flag_, gap_flag_, swap_flag_, xlist, *frame_.get(), frame)) { } } @@ -379,48 +373,65 @@ void write_dcd_hdr(std::ofstream& out, const mol::CoordGroupHandle& coord_group, unsigned int stepsize) { + // size of first header block in bytes int32_t magic_number=84; - char crd[]={'C', 'O', 'R', 'D'}; out.write(reinterpret_cast<char*>(&magic_number), 4); + + // magic string + char crd[]={'C', 'O', 'R', 'D'}; out.write(crd, 4); + + // icntrl[0], NSET, number of frames int32_t num_frames=coord_group.GetFrameCount()/stepsize; out.write(reinterpret_cast<char*>(&num_frames), 4); + + // icntrl[1], ISTART, starting timestep int32_t zero=0; - // write zero for istart out.write(reinterpret_cast<char*>(&zero), 4); + + // icntrl[2], NSAVC, timesteps between DCD saves int32_t one=1; - // number of timesteps between dcd saves. out.write(reinterpret_cast<char*>(&one), 4); - // write spacer of 5 blank integers - for (int i=0; i<5; ++i) { + + // icntrl[3] to icntrl[7], unused + for (int i=3; i<=7; ++i) { out.write(reinterpret_cast<char*>(&zero), 4); } - // write number of fixed atoms + // icntrl[8], NAMNF, number of fixed atoms out.write(reinterpret_cast<char*>(&zero), 4); + + // icntrl[9], DELTA, timestep as float for CHARMM format float delta=1.0; out.write(reinterpret_cast<char*>(&delta), 4); - // write spacer of 10 blank integers - for (int i=0; i <10; ++i) { + + // icntrl[10], CHARMM format: ucell per frame + out.write(reinterpret_cast<char*>(&one), 4); + + // icntrl[11] to icntrl[18], unused + for (int i=11; i<=18; ++i) { out.write(reinterpret_cast<char*>(&zero), 4); } + + // icntrl[19], charmm version + int32_t charmm_version=24; + out.write(reinterpret_cast<char*>(&charmm_version), 4); + // bracket first header block out.write(reinterpret_cast<char*>(&magic_number), 4); - // we don't write any titles for now. This means that the block has only to - // accomodate one int, harr, harr, harr. - int32_t title_block_size=4; - out.write(reinterpret_cast<char*>(&title_block_size), 4); - out.write(reinterpret_cast<char*>(&zero), 4); + + // no titles in title block int32_t four=4; - // again block size for titles? out.write(reinterpret_cast<char*>(&four), 4); - // has to be 4 + out.write(reinterpret_cast<char*>(&zero), 4); + out.write(reinterpret_cast<char*>(&four), 4); + + // atom count block out.write(reinterpret_cast<char*>(&four), 4); int32_t atom_count=coord_group.GetAtomCount(); out.write(reinterpret_cast<char*>(&atom_count), 4); out.write(reinterpret_cast<char*>(&four), 4); } - -} +} // anon ns void SaveCHARMMTraj(const mol::CoordGroupHandle& coord_group, const String& pdb_filename, const String& dcd_filename, @@ -442,10 +453,26 @@ void SaveCHARMMTraj(const mol::CoordGroupHandle& coord_group, int32_t out_n=atom_count*4; for (int i=0; i<frame_count; i+=stepsize) { mol::CoordFramePtr frame=coord_group.GetFrame(i); + + // ucell + int32_t bsize=48; // ucell block size, 6 doubles + geom::Vec3 csize=frame->GetCellSize(); + geom::Vec3 cangles=frame->GetCellAngles(); + // a,alpha,b,beta,gamma,c (don't ask) + double ucell[]={csize[0], + cos(cangles[0]), + csize[1], + cos(cangles[1]), + cos(cangles[2]), + csize[2]}; + out.write(reinterpret_cast<char*>(&bsize),4); + out.write(reinterpret_cast<char*>(ucell),bsize); + out.write(reinterpret_cast<char*>(&bsize),4); + + int k=0; for (mol::CoordFrame::iterator j=frame->begin(), e=frame->end(); j!=e; ++j, ++k) { - //geom::Vec3 v=*j; x[k]=float((*j)[0]); y[k]=float((*j)[1]); z[k]=float((*j)[2]); diff --git a/modules/io/tests/CMakeLists.txt b/modules/io/tests/CMakeLists.txt index 98f075bd9785c1c051f642e3be91dd2e125cc62f..9ac4ba1342db1995749b5cce02a1c89fa278b536 100644 --- a/modules/io/tests/CMakeLists.txt +++ b/modules/io/tests/CMakeLists.txt @@ -4,6 +4,7 @@ set(OST_IO_UNIT_TESTS test_clustal.cc test_io_pdb.cc test_io_crd.cc + test_io_dcd.cc test_io_sdf.cc test_pir.cc test_iomanager.cc diff --git a/modules/io/tests/test_io_dcd.cc b/modules/io/tests/test_io_dcd.cc new file mode 100644 index 0000000000000000000000000000000000000000..5bfd0161f354155527dff2d79e7b24a02fb9ca8e --- /dev/null +++ b/modules/io/tests/test_io_dcd.cc @@ -0,0 +1,88 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2011 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +#include <ost/io/mol/dcd_io.hh> +#include <ost/mol/entity_handle.hh> +#include <ost/mol/residue_handle.hh> +#include <ost/mol/chain_handle.hh> +#include <ost/mol/atom_handle.hh> +#include <ost/mol/xcs_editor.hh> +#include <ost/mol/coord_group.hh> +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> + +using namespace ost; +using namespace ost::io; + +#include <boost/random.hpp> +namespace { + boost::mt19937 RandomGenerator(time(NULL)); + boost::uniform_01<boost::mt19937> UniformRandom(RandomGenerator); +} + +BOOST_AUTO_TEST_SUITE( io ) + +BOOST_AUTO_TEST_CASE(test_io_dcd_charmm_frames) +{ + mol::EntityHandle eh=mol::CreateEntity(); + mol::XCSEditor ed=eh.EditXCS(); + mol::ChainHandle chain=ed.InsertChain("A"); + mol::ResidueHandle res=ed.AppendResidue(chain,mol::ResidueKey("UNK")); + + static unsigned int natoms=13; + + // create atoms and frame coords at the same time + mol::AtomHandleList atoms(natoms); + geom::Vec3List atom_pos(natoms); + std::ostringstream aname; + geom::Vec3 apos1,apos2; + for(size_t i=0;i<natoms;++i) { + for(size_t k=0;k<3;++k) { + apos1[k]=UniformRandom(); + apos2[k]=UniformRandom(); + } + aname.str(""); + aname << "X" << i; + mol::AtomHandle atom=ed.InsertAtom(res,aname.str(),apos1); + atom_pos[i]=apos2; + atoms[i]=atom; + } + geom::Vec3 cell_size(UniformRandom(),UniformRandom(),UniformRandom()); + geom::Vec3 cell_angles(M_PI*UniformRandom(),M_PI*UniformRandom(),M_PI*UniformRandom()); + + mol::CoordGroupHandle cg=mol::CreateCoordGroup(atoms); + cg.AddFrame(atom_pos,cell_size,cell_angles); + + SaveCHARMMTraj(cg,"test_io_dcd_out.pdb","test_io_dcd_out.dcd"); + mol::CoordGroupHandle cg2=LoadCHARMMTraj(eh,"test_io_dcd_out.dcd"); + BOOST_CHECK_EQUAL(cg2.GetAtomCount(),natoms); + BOOST_CHECK_EQUAL(cg2.GetFrameCount(),1); + + mol::CoordFramePtr cf2 = cg2.GetFrame(0); + BOOST_CHECK(geom::Distance(cf2->GetCellSize(),cell_size)<1e-6); + BOOST_CHECK(geom::Distance(cf2->GetCellAngles(),cell_angles)<1e-6); + + geom::Vec3List atom_pos2=cg2.GetFramePositions(0); + + for(size_t i=0;i<natoms;++i) { + BOOST_CHECK(geom::Distance(atom_pos[i],atom_pos2[i])<1e-6); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/modules/mol/base/pymod/export_coord_frame.cc b/modules/mol/base/pymod/export_coord_frame.cc index 1f417064dd8cb2df0ee01956b1f0d0352c6c281f..e3e269e7d7054817d18a3ae642c0e3065846186c 100644 --- a/modules/mol/base/pymod/export_coord_frame.cc +++ b/modules/mol/base/pymod/export_coord_frame.cc @@ -16,6 +16,11 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ + +/* + Authors: Marco Biasini, Niklaus Johner, Ansgar Philippsen +*/ + #include <boost/python.hpp> using namespace boost::python; @@ -26,28 +31,44 @@ using namespace boost::python; using namespace ost; using namespace ost::mol; -geom::Vec3 (CoordFrame::*GetCellSize)() = &CoordFrame::GetCellSize; -geom::Vec3 (CoordFrame::*GetCellAngles)() = &CoordFrame::GetCellAngles; -geom::Vec3 (CoordFrame::*get_atom_pos)(const AtomHandle& atom) = &CoordFrame::GetAtomPos; -Real (CoordFrame::*get_dist_atom)(const AtomHandle& a1, const AtomHandle& a2) = &CoordFrame::GetDistanceBetwAtoms; -Real (CoordFrame::*get_angle)(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3) = &CoordFrame::GetAngle; -Real (CoordFrame::*get_dihedral)(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3, const AtomHandle& a4) = &CoordFrame::GetDihedralAngle; -geom::Vec3 (CoordFrame::*get_cm)(const mol::EntityView& sele) = &CoordFrame::GetCenterOfMassPos; -Real (CoordFrame::*get_dist_cm)(const mol::EntityView& sele1, const mol::EntityView& sele2) = &CoordFrame::GetDistanceBetwCenterOfMass; -Real (CoordFrame::*get_min_dist_cm_v)(const mol::EntityView& sele1, const mol::EntityView& sele2) = &CoordFrame::GetMinDistBetwCenterOfMassAndView; -Real (CoordFrame::*get_rmsd)(const mol::EntityView& Reference_View, const mol::EntityView& sele_View) = &CoordFrame::GetRMSD; -Real (CoordFrame::*get_min_dist)(const mol::EntityView& view1, const mol::EntityView& view2) = &CoordFrame::GetMinDistance; -Real (CoordFrame::*get_alpha)(const mol::EntityView& segment) = &CoordFrame::GetAlphaHelixContent; -geom::Line3 (CoordFrame::*get_odr_line)(const mol::EntityView& view1) = &CoordFrame::GetODRLine; -geom::Line3 (CoordFrame::*get_odr_line2)() = &geom::Vec3List::GetODRLine; -geom::Plane (CoordFrame::*get_odr_plane)(const mol::EntityView& view1) = &CoordFrame::GetODRPlane; -geom::Line3 (CoordFrame::*fit_cylinder)(const mol::EntityView& view1) = &CoordFrame::FitCylinder; +geom::Vec3 (CoordFrame::*get_atom_pos)(const AtomHandle&) const = &CoordFrame::GetAtomPos; +Real (CoordFrame::*get_dist_atom)(const AtomHandle&, const AtomHandle&) const = &CoordFrame::GetDistanceBetwAtoms; +Real (CoordFrame::*get_angle)(const AtomHandle&, const AtomHandle&, const AtomHandle&) const = &CoordFrame::GetAngle; +Real (CoordFrame::*get_dihedral)(const AtomHandle&, const AtomHandle&, const AtomHandle&, const AtomHandle&) const = &CoordFrame::GetDihedralAngle; +geom::Vec3 (CoordFrame::*get_cm)(const mol::EntityView&) const = &CoordFrame::GetCenterOfMassPos; +Real (CoordFrame::*get_dist_cm)(const mol::EntityView&, const mol::EntityView&) const = &CoordFrame::GetDistanceBetwCenterOfMass; +Real (CoordFrame::*get_min_dist_cm_v)(const mol::EntityView&, const mol::EntityView&) const = &CoordFrame::GetMinDistBetwCenterOfMassAndView; +Real (CoordFrame::*get_rmsd)(const mol::EntityView&, const mol::EntityView&) const = &CoordFrame::GetRMSD; +Real (CoordFrame::*get_min_dist)(const mol::EntityView&, const mol::EntityView&) const = &CoordFrame::GetMinDistance; +Real (CoordFrame::*get_alpha)(const mol::EntityView&) const = &CoordFrame::GetAlphaHelixContent; +geom::Line3 (CoordFrame::*get_odr_line)(const mol::EntityView&) const = &CoordFrame::GetODRLine; +geom::Plane (CoordFrame::*get_odr_plane)(const mol::EntityView&) const = &CoordFrame::GetODRPlane; +geom::Line3 (CoordFrame::*fit_cylinder)(const mol::EntityView&) const = &CoordFrame::FitCylinder; +// TODO: move to geom +geom::Line3 (CoordFrame::*get_odr_line2)() const = &geom::Vec3List::GetODRLine; + +CoordFrame create_coord_frame1(const geom::Vec3List& atom_pos) +{ + return CreateCoordFrame(atom_pos); +} + +CoordFrame create_coord_frame2(const geom::Vec3List& atom_pos, + const geom::Vec3& cell_size, + const geom::Vec3& cell_angles) +{ + return CreateCoordFrame(atom_pos,cell_size,cell_angles); +} void export_CoordFrame() { - class_<CoordFrame>("CoordFrame",no_init) - .def("GetCellSize",GetCellSize) - .def("GetCellAngles",GetCellAngles) + // TODO: add ctors or factory functions that take python sequences + class_<CoordFrame>("CoordFrame",init<size_t, optional<geom::Vec3> >()) + .def("SetCellSize",&CoordFrame::SetCellSize) + .def("GetCellSize",&CoordFrame::GetCellSize) + .add_property("cell_size",&CoordFrame::GetCellSize,&CoordFrame::SetCellSize) + .def("SetCellAngles",&CoordFrame::SetCellAngles) + .def("GetCellAngles",&CoordFrame::GetCellAngles) + .add_property("cell_angles",&CoordFrame::GetCellAngles,&CoordFrame::SetCellAngles) .def("GetAtomPos", get_atom_pos) .def("GetDistanceBetwAtoms", get_dist_atom) .def("GetAngle", get_angle) @@ -63,5 +84,6 @@ void export_CoordFrame() .def("GetAlphaHelixContent",get_alpha) .def("FitCylinder",fit_cylinder) ; - def("CreateCoordFrame",CreateCoordFrame); + def("CreateCoordFrame",create_coord_frame1); + def("CreateCoordFrame",create_coord_frame2); } diff --git a/modules/mol/base/src/coord_frame.cc b/modules/mol/base/src/coord_frame.cc index 71b9ed9a64d4f21eeed7630e886f47c02ee96d8e..1c30611b3b82a75ffd6660c6980183a0a94e5663 100644 --- a/modules/mol/base/src/coord_frame.cc +++ b/modules/mol/base/src/coord_frame.cc @@ -18,8 +18,8 @@ //------------------------------------------------------------------------------ /* - Author: Niklaus Johner - */ + Authors: Niklaus Johner, Ansgar Philippsen +*/ #include <ost/invalid_handle.hh> #include <ost/integrity_error.hh> @@ -32,147 +32,76 @@ namespace ost { namespace mol { - CoordFrame CreateCoordFrame(const geom::Vec3List& atom_pos) - { - return CoordFrame(atom_pos); + namespace { + /* + Returns a score between 0 and 1 measuring the distance between + a pair of angles and a pair of reference angles + */ + Real Eval2AngleDist(Real phi, Real phi0, Real psi, Real psi0, Real delta) + { + Real d1,d2,d; + d1=abs(phi-phi0); + d2=abs(psi-psi0); + if (d1>M_PI) d1=abs(d1-2.*M_PI); + if (d2>M_PI) d1=abs(d2-2.*M_PI); + d=(pow(d1,2.)+pow(d2,2.))/pow(delta,2.); + return 1./(1+d); + } } - - geom::Vec3 CoordFrame::GetAtomPos(const AtomHandle& atom){ - //Returns the position of the atom in this frame + + geom::Vec3 CoordFrame::GetAtomPos(const AtomHandle& atom) const + { return this->GetAtomPos(atom.GetIndex()); } - geom::Vec3 CoordFrame::GetAtomPos(int i1){ - //Returns the position in this frame of the atom with index i1 + + geom::Vec3 CoordFrame::GetAtomPos(int i1) const + { return (*this)[i1]; } - Real CoordFrame::GetDistanceBetwAtoms(const AtomHandle& a1, const AtomHandle& a2){ - //Return the distance in this frame between two atoms + Real CoordFrame::GetDistanceBetwAtoms(const AtomHandle& a1, const AtomHandle& a2) const + { return this->GetDistanceBetwAtoms(a1.GetIndex(),a2.GetIndex()); } - Real CoordFrame::GetDistanceBetwAtoms(int i1, int i2){ - //Return the distance in this frame between the two atoms with indices i1 and i2 + + Real CoordFrame::GetDistanceBetwAtoms(int i1, int i2) const + { return geom::Distance((*this)[i1],(*this)[i2]); } - Real CoordFrame::GetAngle(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3){ - //Returns the Angle between the three atoms, a2 being considered as the central atom - //i.e the angle between the vector (a1.pos-a2.pos) and (a3.pos-a2.pos) + Real CoordFrame::GetAngle(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3) const + { return this->GetAngle(a1.GetIndex(),a2.GetIndex(),a3.GetIndex()); } - Real CoordFrame::GetAngle(int i1, int i2, int i3){ - //Returns the angl between the three atoms with indices i1,i2,i3 + + Real CoordFrame::GetAngle(int i1, int i2, int i3) const + { return geom::Angle((*this)[i1]-(*this)[i2],(*this)[i3]-(*this)[i2]); } Real CoordFrame::GetDihedralAngle(const AtomHandle& a1, const AtomHandle& a2, - const AtomHandle& a3, const AtomHandle& a4){ - //Returns the Dihedral angle between the four atoms a1,a2,a3,a4 + const AtomHandle& a3, const AtomHandle& a4) const + { return this->GetDihedralAngle(a1.GetIndex(),a2.GetIndex(),a3.GetIndex(),a4.GetIndex()); } - Real CoordFrame::GetDihedralAngle(int i1, int i2, int i3, int i4){ - //Returns the Dihedral angle between the four atoms with indices i1,i2,i3,i4 - return geom::DihedralAngle((*this)[i1],(*this)[i2],(*this)[i3],(*this)[i4]); - } - void GetIndices(const EntityView& sele, std::vector<unsigned long>& indices){ - // This function returns a vector containing the atom indices of the atoms in an EntityView - // It is used to accelerate the extraction of information from a trajectory - AtomViewList atoms=sele.GetAtomList(); - indices.reserve(atoms.size()); - for (AtomViewList::const_iterator i=atoms.begin(), - e=atoms.end(); i!=e; ++i) { - indices.push_back(i->GetIndex()); - } - } - - void GetCaIndices(const EntityView& segment, std::vector<unsigned long>& indices_ca){ - mol::AtomView ca; - ResidueViewList residues=segment.GetResidueList(); - indices_ca.reserve(residues.size()); - //for (ResidueViewList::const_iterator res=residues.begin()+1, - // e=residues.end(); res!=e-1; ++res){ - // if (!InSequence((*res).GetHandle(),(*(res+1)).GetHandle())) throw std::runtime_error("Residues are not in a continuous sequence"); - //} - for (ResidueViewList::const_iterator res=residues.begin(), - e=residues.end(); res!=e; ++res) { - ca=res->FindAtom("CA"); - CheckHandleValidity(ca); - indices_ca.push_back(ca.GetIndex()); - } - } - - void GetCaCONIndices(const EntityView& segment, std::vector<unsigned long>& indices_ca, - std::vector<unsigned long>& indices_c, std::vector<unsigned long>& indices_o, std::vector<unsigned long>& indices_n){ - mol::AtomView a,n,c,o; - ResidueViewList residues=segment.GetResidueList(); - indices_ca.reserve(residues.size()); - indices_n.reserve(residues.size()); - indices_c.reserve(residues.size()); - indices_o.reserve(residues.size()); - for (ResidueViewList::const_iterator res=residues.begin()+1, - e=residues.end(); res!=e-1; ++res){ - if (!InSequence((*res).GetHandle(),(*(res+1)).GetHandle())) throw std::runtime_error("Residues are not in a continuous sequence"); - } - for (ResidueViewList::const_iterator res=residues.begin(), - e=residues.end(); res!=e; ++res) { - a=res->FindAtom("CA"); - CheckHandleValidity(a); - indices_ca.push_back(a.GetIndex()); - c=res->FindAtom("C"); - CheckHandleValidity(c); - indices_c.push_back(c.GetIndex()); - o=res->FindAtom("O"); - CheckHandleValidity(o); - indices_o.push_back(o.GetIndex()); - n=res->FindAtom("N"); - CheckHandleValidity(n); - indices_n.push_back(n.GetIndex()); - } + Real CoordFrame::GetDihedralAngle(int i1, int i2, int i3, int i4) const + { + return geom::DihedralAngle((*this)[i1],(*this)[i2],(*this)[i3],(*this)[i4]); } - void GetMasses(const EntityView& sele, std::vector<Real>& masses){ - // This function returns a vector containing the atom masses of the atoms in an EntityView - // It is used together with GetIndices to accelerate the extraction of RMSD from a trajectory - Real mass_tot=0.0; - AtomViewList atoms=sele.GetAtomList(); - masses.reserve(atoms.size()); - for (AtomViewList::const_iterator i=atoms.begin(), - e=atoms.end(); i!=e; ++i) { - masses.push_back(i->GetMass()); - mass_tot=mass_tot+i->GetMass(); - } - for (std::vector<Real>::iterator - j=masses.begin(), e2=masses.end(); j!=e2; ++j) { - (*j)/=mass_tot; - } - } - - void GetIndicesAndMasses(const EntityView& sele, std::vector<unsigned long>& indices,std::vector<Real>& masses){ - GetIndices(sele, indices); - GetMasses(sele, masses); - } - - void GetPositions(const EntityView& sele, std::vector<geom::Vec3>& ref_pos){ - //Returns the positions of all the atoms in the EntityView - ref_pos.reserve(sele.GetAtomCount()); - for (mol::AtomViewIter a=sele.AtomsBegin(),e=sele.AtomsEnd(); a!=e; ++a) { - ref_pos.push_back((*a).GetPos()); - } - } - - geom::Vec3 CoordFrame::GetCenterOfMassPos(const EntityView& sele){ - //Returns the position of the centor of mass of the atoms in the EntityView + geom::Vec3 CoordFrame::GetCenterOfMassPos(const EntityView& sele) const + { std::vector<unsigned long> indices; std::vector<Real> masses; GetIndicesAndMasses(sele,indices,masses); return this->GetCenterOfMassPos(indices,masses); } - geom::Vec3 CoordFrame::GetCenterOfMassPos(std::vector<unsigned long>& indices,std::vector<Real>& masses){ - //Returns the position of the centor of mass of the atoms from which the indices and masses are passed - //as vectors in argument + geom::Vec3 CoordFrame::GetCenterOfMassPos(std::vector<unsigned long>& indices, + std::vector<Real>& masses) const + { geom::Vec3 v; for (unsigned int i=0,e=indices.size();i!=e; i++) { v+=masses[i]*(*this)[indices[i]]; @@ -180,8 +109,8 @@ namespace ost { namespace mol { return v; } - Real CoordFrame::GetDistanceBetwCenterOfMass(const EntityView& sele1,const EntityView& sele2){ - //Returns the distance between the centers of mass of the two EntityViews + Real CoordFrame::GetDistanceBetwCenterOfMass(const EntityView& sele1,const EntityView& sele2) const + { std::vector<unsigned long> indices1,indices2; std::vector<Real> masses1,masses2; GetIndicesAndMasses(sele1,indices1,masses1); @@ -189,18 +118,19 @@ namespace ost { namespace mol { return this->GetDistanceBetwCenterOfMass(indices1,masses1,indices2,masses2); } - Real CoordFrame::GetDistanceBetwCenterOfMass(std::vector<unsigned long>& indices1,std::vector<Real>& masses1, - std::vector<unsigned long>& indices2,std::vector<Real>& masses2){ - //Returns the distance between the centers of mass of the two groups of atoms from which the - //indices and masses are given as vectors as argument + Real CoordFrame::GetDistanceBetwCenterOfMass(std::vector<unsigned long>& indices1, + std::vector<Real>& masses1, + std::vector<unsigned long>& indices2, + std::vector<Real>& masses2) const + { geom::Vec3 v1=this->GetCenterOfMassPos(indices1, masses1); geom::Vec3 v2=this->GetCenterOfMassPos(indices2, masses2); return geom::Distance(v1,v2); } - Real CoordFrame::GetRMSD(const std::vector<geom::Vec3>& ref_pos,const std::vector<unsigned long>& indices_sele){ - //Returns the RMSD between the positions of the atoms whose indices are given in indices_sele and the positions - //given in ref_pos + Real CoordFrame::GetRMSD(const std::vector<geom::Vec3>& ref_pos, + const std::vector<unsigned long>& indices_sele) const + { Real rmsd=0.0,val; for (unsigned int i1=0; i1!=indices_sele.size(); ++i1) { geom::Vec3 av_sele=(*this)[indices_sele[i1]]; @@ -211,9 +141,8 @@ namespace ost { namespace mol { return pow(rmsd/indices_sele.size(),0.5); } - Real CoordFrame::GetRMSD(const EntityView& reference_view,const EntityView& sele_view){ - //Return the rmsd between two EntityViews. The reference positions are taken directly from the reference_view - //whereas they are taken from this CoordFrame for the sele_view + Real CoordFrame::GetRMSD(const EntityView& reference_view,const EntityView& sele_view) const + { int count_ref=reference_view.GetAtomCount(); int count_sele=sele_view.GetAtomCount(); if (count_ref!=count_sele){ @@ -226,8 +155,9 @@ namespace ost { namespace mol { return this->GetRMSD(ref_pos,indices_sele); } - Real CoordFrame::GetMinDistance(std::vector<unsigned long>& index_list1, std::vector<unsigned long>& index_list2){ - //Returns the minimal distance between two groups of atoms with indices given by index_list1 and index_list2 + Real CoordFrame::GetMinDistance(std::vector<unsigned long>& index_list1, + std::vector<unsigned long>& index_list2) const + { geom::Vec3List pos_list1,pos_list2; for (std::vector<unsigned long>::const_iterator i1=index_list1.begin(),e=index_list1.end(); i1!=e; ++i1) { pos_list1.push_back((*this)[*i1]); @@ -237,18 +167,19 @@ namespace ost { namespace mol { } return geom::MinDistance(pos_list1,pos_list2); } - Real CoordFrame::GetMinDistance(const mol::EntityView& view1, const mol::EntityView& view2){ - //Returns the minimal distance between the atoms of two views (view1 and view2) + + Real CoordFrame::GetMinDistance(const mol::EntityView& view1, const mol::EntityView& view2) const + { std::vector<unsigned long> index_list1,index_list2; GetIndices(view1,index_list1); GetIndices(view2,index_list2); return this->GetMinDistance(index_list1,index_list2); } - Real CoordFrame::GetMinDistBetwCenterOfMassAndView(std::vector<unsigned long>& indices_cm, std::vector<Real>& masses_cm, - std::vector<unsigned long>& indices_atoms){ - //Returns the minimal distance between the center of mass of a group of atoms (with indices given in indices_cm and masses - //in masses_cm) and the atoms of another group (with indices given in indices_atoms) + Real CoordFrame::GetMinDistBetwCenterOfMassAndView(std::vector<unsigned long>& indices_cm, + std::vector<Real>& masses_cm, + std::vector<unsigned long>& indices_atoms) const + { geom::Vec3List cm_pos,atoms_pos_list; cm_pos.push_back(this->GetCenterOfMassPos(indices_cm, masses_cm)); for (std::vector<unsigned long>::const_iterator i1=indices_atoms.begin(),e=indices_atoms.end(); i1!=e; ++i1) { @@ -256,8 +187,10 @@ namespace ost { namespace mol { } return geom::MinDistance(cm_pos,atoms_pos_list); } - Real CoordFrame::GetMinDistBetwCenterOfMassAndView(const mol::EntityView& view_cm, const mol::EntityView& view_atoms){ - //Returns the minimal distance between the center of mass of a view (view_cm) and the atoms of another view (view_atoms) + + Real CoordFrame::GetMinDistBetwCenterOfMassAndView(const mol::EntityView& view_cm, + const mol::EntityView& view_atoms) const + { std::vector<unsigned long> indices_cm,indices_atoms; std::vector<Real> masses_cm; GetIndices(view_atoms,indices_atoms); @@ -265,8 +198,8 @@ namespace ost { namespace mol { return this->GetMinDistBetwCenterOfMassAndView(indices_cm,masses_cm,indices_atoms); } - geom::Line3 CoordFrame::GetODRLine(std::vector<unsigned long>& indices_ca){ - //Returns the best fit line to atoms with indices in indices_ca + geom::Line3 CoordFrame::GetODRLine(std::vector<unsigned long>& indices_ca) const + { geom::Vec3List atoms_pos_list; atoms_pos_list.reserve(indices_ca.size()); for (std::vector<unsigned long>::const_iterator i1=indices_ca.begin(),e=indices_ca.end(); i1!=e; ++i1) { @@ -275,15 +208,14 @@ namespace ost { namespace mol { return atoms_pos_list.GetODRLine(); } - geom::Line3 CoordFrame::GetODRLine(const mol::EntityView& view1){ - //Returns the best fit line to atoms in the EntityView view1 + geom::Line3 CoordFrame::GetODRLine(const mol::EntityView& view1) const { std::vector<unsigned long> indices; GetIndices(view1,indices); return this->GetODRLine(indices); } - geom::Plane CoordFrame::GetODRPlane(std::vector<unsigned long>& indices_ca){ - //Returns the normal to the best fit plane to atoms with indices in indices_ca + geom::Plane CoordFrame::GetODRPlane(std::vector<unsigned long>& indices_ca) const + { geom::Vec3List atoms_pos_list; atoms_pos_list.reserve(indices_ca.size()); for (std::vector<unsigned long>::const_iterator i1=indices_ca.begin(),e=indices_ca.end(); i1!=e; ++i1) { @@ -292,17 +224,14 @@ namespace ost { namespace mol { return atoms_pos_list.GetODRPlane(); } - geom::Plane CoordFrame::GetODRPlane(const mol::EntityView& view1){ - //Returns the best fit plane to atoms in the EntityView view1 + geom::Plane CoordFrame::GetODRPlane(const mol::EntityView& view1) const + { std::vector<unsigned long> indices; GetIndices(view1,indices); return this->GetODRPlane(indices); } - geom::Line3 CoordFrame::FitCylinder(std::vector<unsigned long>& indices_ca){ - //Returns a line which is the axis of a fitted cylinder to the atoms with indices given in indices_ca - //It is assumed that we fit an alpha-helix and that the CA atoms are oredered sequentially - //This is used for the initial guess of the helix axis + geom::Line3 CoordFrame::FitCylinder(std::vector<unsigned long>& indices_ca) const { geom::Vec3List atoms_pos_list; int n_atoms=indices_ca.size(); atoms_pos_list.reserve(n_atoms); @@ -326,99 +255,174 @@ namespace ost { namespace mol { return atoms_pos_list.FitCylinder(initial_axis,center); } - geom::Line3 CoordFrame::FitCylinder(const mol::EntityView& view1){ - // Return a lin which is the axis of the best fit cylinder to the CA atoms - // of the EntityView. - // It is assumed that we fit an alpha-helix and that the CA atoms are oredered sequentially + geom::Line3 CoordFrame::FitCylinder(const mol::EntityView& view1) const { CheckHandleValidity(view1); std::vector<unsigned long> indices_ca; GetCaIndices(view1, indices_ca); return CoordFrame::FitCylinder(indices_ca); } - Real CoordFrame::GetAlphaHelixContent(const mol::EntityView& segment){ - //Returns the percentage of residues in the EntityView (segment) that are in an alpha-helix - //Each residue is assigned as being in an alpha-helix or not, based on and backbone torsion angles - //and the hydrogen bonding (O-N) (this term is used only if the segment contains at least 8 residues - //The entity view should be a single segment with no gaps and no missing N,CA,C,O backbone atoms - //the first and last residues will not be asessed for helicity + Real CoordFrame::GetAlphaHelixContent(const mol::EntityView& segment) const + { CheckHandleValidity(segment); std::vector<unsigned long> indices_c, indices_n, indices_ca, indices_o; GetCaCONIndices(segment, indices_ca, indices_c, indices_o, indices_n); return CoordFrame::GetAlphaHelixContent(indices_ca,indices_c,indices_o,indices_n); } - Real Eval2AngleDist(Real phi, Real phi0, Real psi, Real psi0, Real delta){ - //Returns a score between 0 and 1 measuring the distance between - //a pair of angles and a pair of reference angles - Real d1,d2,d; - d1=abs(phi-phi0); - d2=abs(psi-psi0); - if (d1>M_PI) d1=abs(d1-2.*M_PI); - if (d2>M_PI) d1=abs(d2-2.*M_PI); - d=(pow(d1,2.)+pow(d2,2.))/pow(delta,2.); - return 1./(1+d); + Real CoordFrame::GetAlphaHelixContent(std::vector<unsigned long>& indices_ca, + std::vector<unsigned long>& indices_c, + std::vector<unsigned long>& indices_o, + std::vector<unsigned long>& indices_n) const + { + //See CoordFrame::GetAlphaHelixContent(const mol::EntityView) above. + unsigned long n_atoms=indices_ca.size(); + geom::Vec3 c_previous,n,ca,c,n_next; + Real phi,psi,phi_0=-1.2,psi_0=-0.785,delta=0.8,d_0=3.3; + unsigned long n_helical_res=0; + std::vector<Real> score,dist,score2,dist2; + score.reserve(n_atoms-2); + score2.reserve(n_atoms-2); + dist.reserve(n_atoms-2); + dist2.reserve(n_atoms-2); + if (n_atoms!=indices_n.size()||n_atoms!=indices_c.size()||n_atoms!=indices_o.size()){ + throw std::runtime_error("not same numbers of CA, C, O and N atoms in the selection"); + } + if (n_atoms<=5){ + throw std::runtime_error("At least five residues are needed to calulate an alpha helix similarity"); + } + c=(*this)[indices_c[0]]; + n_next=(*this)[indices_n[1]]; + for (unsigned long i=1; i!=n_atoms-1; ++i) { + c_previous=c; + n=n_next; + ca=(*this)[indices_ca[i]]; + c=(*this)[indices_c[i]]; + n_next=(*this)[indices_n[i+1]]; + phi=geom::DihedralAngle(c_previous,n,ca,c); + psi=geom::DihedralAngle(n,ca,c,n_next); + score.push_back(Eval2AngleDist(phi,phi_0,psi,psi_0,delta)); + } + score2[0]=pow(score[0]*score[1],3./2.); + score2[n_atoms-3]=pow(score[n_atoms-3]*score[n_atoms-4],3./2.); + for (unsigned long i=1; i!=n_atoms-3; ++i) { + score2[i]=score[i-1]*score[i]*score[i+1]; + } + if (n_atoms>=8){ + for (unsigned long i=1; i!=n_atoms-1; ++i){ + if (i<n_atoms-4){ + dist.push_back(geom::Distance((*this)[indices_o[i]],(*this)[indices_n[i+4]])); + if (i>=5) { + dist2.push_back(std::min(dist[i-1],dist[i-5])); + } else { + dist2.push_back(dist[i-1]); + } + } else { + dist2.push_back(geom::Distance((*this)[indices_n[i]],(*this)[indices_o[i-4]])); + } + } + for (unsigned long i=0; i!=n_atoms-2; ++i){ + if (dist2[i]<=d_0 || score2[i]>=0.3) { + n_helical_res+=1; + } + } + } else { + for (unsigned long i=0; i!=n_atoms-2; ++i){ + if (score2[i]>=0.3) { + n_helical_res+=1; + } + } + } + return Real(n_helical_res)/Real(n_atoms-2); + } + + CoordFrame CreateCoordFrame(const geom::Vec3List& atom_pos, const geom::Vec3& cs, const geom::Vec3& ca) + { + return CoordFrame(atom_pos,cs,ca); } - Real CoordFrame::GetAlphaHelixContent(std::vector<unsigned long>& indices_ca, std::vector<unsigned long>& indices_c, - std::vector<unsigned long>& indices_o, std::vector<unsigned long>& indices_n){ - //See CoordFrame::GetAlphaHelixContent(const mol::EntityView) above. - unsigned long n_atoms=indices_ca.size(); - geom::Vec3 c_previous,n,ca,c,n_next; - Real phi,psi,phi_0=-1.2,psi_0=-0.785,delta=0.8,d_0=3.3; - unsigned long n_helical_res=0; - std::vector<Real> score,dist,score2,dist2; - score.reserve(n_atoms-2); - score2.reserve(n_atoms-2); - dist.reserve(n_atoms-2); - dist2.reserve(n_atoms-2); - if (n_atoms!=indices_n.size()||n_atoms!=indices_c.size()||n_atoms!=indices_o.size()){ - throw std::runtime_error("not same numbers of CA, C, O and N atoms in the selection"); - } - if (n_atoms<=5){ - throw std::runtime_error("At least five residues are needed to calulate an alpha helix similarity"); - } - c=(*this)[indices_c[0]]; - n_next=(*this)[indices_n[1]]; - for (unsigned long i=1; i!=n_atoms-1; ++i){ - c_previous=c; - n=n_next; - ca=(*this)[indices_ca[i]]; - c=(*this)[indices_c[i]]; - n_next=(*this)[indices_n[i+1]]; - phi=geom::DihedralAngle(c_previous,n,ca,c); - psi=geom::DihedralAngle(n,ca,c,n_next); - score.push_back(Eval2AngleDist(phi,phi_0,psi,psi_0,delta)); - } - score2[0]=pow(score[0]*score[1],3./2.); - score2[n_atoms-3]=pow(score[n_atoms-3]*score[n_atoms-4],3./2.); - for (unsigned long i=1; i!=n_atoms-3; ++i){ - score2[i]=score[i-1]*score[i]*score[i+1]; - } - if (n_atoms>=8){ - for (unsigned long i=1; i!=n_atoms-1; ++i){ - if (i<n_atoms-4){ - dist.push_back(geom::Distance((*this)[indices_o[i]],(*this)[indices_n[i+4]])); - if (i>=5) { - dist2.push_back(std::min(dist[i-1],dist[i-5])); - } - else dist2.push_back(dist[i-1]); + void GetIndices(const EntityView& sele, std::vector<unsigned long>& indices) + { + AtomViewList atoms=sele.GetAtomList(); + indices.reserve(atoms.size()); + for (AtomViewList::const_iterator i=atoms.begin(), + e=atoms.end(); i!=e; ++i) { + indices.push_back(i->GetIndex()); + } + } + + void GetCaIndices(const EntityView& segment, std::vector<unsigned long>& indices_ca){ + mol::AtomView ca; + ResidueViewList residues=segment.GetResidueList(); + indices_ca.reserve(residues.size()); + //for (ResidueViewList::const_iterator res=residues.begin()+1, + // e=residues.end(); res!=e-1; ++res){ + // if (!InSequence((*res).GetHandle(),(*(res+1)).GetHandle())) throw std::runtime_error("Residues are not in a continuous sequence"); + //} + for (ResidueViewList::const_iterator res=residues.begin(), + e=residues.end(); res!=e; ++res) { + ca=res->FindAtom("CA"); + CheckHandleValidity(ca); + indices_ca.push_back(ca.GetIndex()); } - else dist2.push_back(geom::Distance((*this)[indices_n[i]],(*this)[indices_o[i-4]])); + } + + void GetCaCONIndices(const EntityView& segment, std::vector<unsigned long>& indices_ca, + std::vector<unsigned long>& indices_c, std::vector<unsigned long>& indices_o, std::vector<unsigned long>& indices_n){ + mol::AtomView a,n,c,o; + ResidueViewList residues=segment.GetResidueList(); + indices_ca.reserve(residues.size()); + indices_n.reserve(residues.size()); + indices_c.reserve(residues.size()); + indices_o.reserve(residues.size()); + for (ResidueViewList::const_iterator res=residues.begin()+1, + e=residues.end(); res!=e-1; ++res){ + if (!InSequence((*res).GetHandle(),(*(res+1)).GetHandle())) throw std::runtime_error("Residues are not in a continuous sequence"); } - for (unsigned long i=0; i!=n_atoms-2; ++i){ - if (dist2[i]<=d_0 || score2[i]>=0.3)n_helical_res+=1; + for (ResidueViewList::const_iterator res=residues.begin(), + e=residues.end(); res!=e; ++res) { + a=res->FindAtom("CA"); + CheckHandleValidity(a); + indices_ca.push_back(a.GetIndex()); + c=res->FindAtom("C"); + CheckHandleValidity(c); + indices_c.push_back(c.GetIndex()); + o=res->FindAtom("O"); + CheckHandleValidity(o); + indices_o.push_back(o.GetIndex()); + n=res->FindAtom("N"); + CheckHandleValidity(n); + indices_n.push_back(n.GetIndex()); } } - else { - for (unsigned long i=0; i!=n_atoms-2; ++i){ - if (score2[i]>=0.3)n_helical_res+=1; + + void GetMasses(const EntityView& sele, std::vector<Real>& masses){ + Real mass_tot=0.0; + AtomViewList atoms=sele.GetAtomList(); + masses.reserve(atoms.size()); + for (AtomViewList::const_iterator i=atoms.begin(), + e=atoms.end(); i!=e; ++i) { + masses.push_back(i->GetMass()); + mass_tot=mass_tot+i->GetMass(); } + for (std::vector<Real>::iterator + j=masses.begin(), e2=masses.end(); j!=e2; ++j) { + (*j)/=mass_tot; + } } - return Real(n_helical_res)/Real(n_atoms-2); + + + void GetIndicesAndMasses(const EntityView& sele, std::vector<unsigned long>& indices,std::vector<Real>& masses){ + GetIndices(sele, indices); + GetMasses(sele, masses); + } + + void GetPositions(const EntityView& sele, std::vector<geom::Vec3>& ref_pos){ + ref_pos.reserve(sele.GetAtomCount()); + for (mol::AtomViewIter a=sele.AtomsBegin(),e=sele.AtomsEnd(); a!=e; ++a) { + ref_pos.push_back((*a).GetPos()); + } } - - }}//ns diff --git a/modules/mol/base/src/coord_frame.hh b/modules/mol/base/src/coord_frame.hh index 98eb0c25c5560dbce0ad43e8450e79b8994b46df..ad76a5dc869d281775ca61fe0ce191fc6a4d8757 100644 --- a/modules/mol/base/src/coord_frame.hh +++ b/modules/mol/base/src/coord_frame.hh @@ -20,7 +20,7 @@ #define OST_MOL_COORD_FRAME_HH /* - Author: Marco Biasini and Niklaus Johner + Authors: Marco Biasini, Niklaus Johner, Ansgar Philippsen */ #include <boost/shared_ptr.hpp> #include <ost/geom/geom.hh> @@ -30,10 +30,22 @@ namespace ost { namespace mol { +/*! + A coordinate frame in a trajectory, containing atom positions and + per-frame unit cell size and angles. +*/ + +/* + TODO: + - move algorithmic code to separate functions in mol/alg + - clean up mix of views and atom indices methods/functions + - use existing UnitCell class +*/ + class DLLEXPORT_OST_MOL CoordFrame : public geom::Vec3List{ private: - geom::Vec3 periodic_cell_sizes_; - geom::Vec3 periodic_cell_angles_; + geom::Vec3 ucell_size_; + geom::Vec3 ucell_angles_; public: typedef geom::Vec3List base_type; @@ -42,62 +54,194 @@ public: CoordFrame(base_type::iterator b, base_type::iterator e): base_type(b, e) { } CoordFrame(const base_type& rhs) : base_type(rhs) { } CoordFrame(const std::vector<geom::Vec3>& rhs) : base_type(rhs) { } - CoordFrame(const std::vector<geom::Vec3>& rhs,const geom::Vec3 box_size, const geom::Vec3 box_angles) : base_type(rhs) { - this->periodic_cell_sizes_=box_size; - this->periodic_cell_angles_=box_angles; + CoordFrame(const std::vector<geom::Vec3>& rhs, + const geom::Vec3 box_size, + const geom::Vec3 box_angles) : base_type(rhs) { + ucell_size_=box_size; + ucell_angles_=box_angles; } - - geom::Vec3 GetCellSize() { - return this->periodic_cell_sizes_; + + void SetCellSize(const geom::Vec3& s) { + ucell_size_=s; } - geom::Vec3 GetCellAngles() { - return this->periodic_cell_angles_; + + geom::Vec3 GetCellSize() const { + return this->ucell_size_; } - geom::Vec3 GetAtomPos(const AtomHandle& atom); - geom::Vec3 GetAtomPos(int atom_index); - Real GetDistanceBetwAtoms(const AtomHandle& a1, const AtomHandle& a2); - Real GetDistanceBetwAtoms(int atom1_index, int atom2_index); - Real GetAngle(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3); - Real GetAngle(int atom1_index, int atom2_index, int atom3_index); - Real GetDihedralAngle(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3, const AtomHandle& a4); - Real GetDihedralAngle(int a1_index, int a2_index, int a3_index, int a4_index); - geom::Vec3 GetCenterOfMassPos(const mol::EntityView& sele); - geom::Vec3 GetCenterOfMassPos(std::vector<unsigned long>& indices, std::vector<Real>& masses); - Real GetDistanceBetwCenterOfMass(const mol::EntityView& sele1, const mol::EntityView& sele2); + + void SetCellAngles(const geom::Vec3& a) { + ucell_angles_=a; + } + + geom::Vec3 GetCellAngles() const { + return this->ucell_angles_; + } + + geom::Vec3 GetAtomPos(const AtomHandle& atom) const; + geom::Vec3 GetAtomPos(int atom_index) const; + Real GetDistanceBetwAtoms(const AtomHandle& a1, const AtomHandle& a2) const; + Real GetDistanceBetwAtoms(int atom1_index, int atom2_index) const; + + /*! + Returns the angle between the three atoms in rad + + a2 is considered the central atom, i.e the result is the angle between + the vectors (a1.pos-a2.pos) and (a3.pos-a2.pos) + */ + Real GetAngle(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3) const; + + /*! + Returns the angle between the three atom indices in rad + + atom2 is considered the central atom, i.e the result is the angle between + the vectors (atom1.pos-atom2.pos) and (atom3.pos-atom2.pos) + */ + Real GetAngle(int atom1_index, int atom2_index, int atom3_index) const; + + //! Returns the Dihedral angle between the four atoms a1,a2,a3,a4 + Real GetDihedralAngle(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3, const AtomHandle& a4) const; + + //! Returns the Dihedral angle between the four atom indices a1,a2,a3,a4 + Real GetDihedralAngle(int a1_index, int a2_index, int a3_index, int a4_index) const; + + //! Returns the position of the centor of mass of the atoms in the EntityView + geom::Vec3 GetCenterOfMassPos(const mol::EntityView& sele) const; + + //! Calculates the center of mass given a list of indices and provided masses + /*! + the masses vector contains only the masses for the atoms indexed by indices, not for + all atoms in the frame + */ + geom::Vec3 GetCenterOfMassPos(std::vector<unsigned long>& indices, + std::vector<Real>& masses) const; + + //! Returns the distance between the centers of mass of the two EntityViews + Real GetDistanceBetwCenterOfMass(const mol::EntityView& sele1, const mol::EntityView& sele2) const; + + /*! Returns the distance betweem two custom center of masses + + Calculates the centers of mass of the two groups of atoms from given by index lists and + custom masses. See comment regarding masses vector for GetCenterOfMassPos + */ Real GetDistanceBetwCenterOfMass(std::vector<unsigned long>& indices1, std::vector<Real>& masses1, - std::vector<unsigned long>& indices2, std::vector<Real>& masses2); - Real GetRMSD(const std::vector<geom::Vec3>& ref_pos, const std::vector<unsigned long>& indices_sele); - Real GetRMSD(const mol::EntityView& reference_view, const mol::EntityView& sele_view); - Real GetMinDistance(std::vector<unsigned long>& index_list1, std::vector<unsigned long>& index_list2); - Real GetMinDistance(const mol::EntityView& view1, const mol::EntityView& view2); - Real GetMinDistBetwCenterOfMassAndView(std::vector<unsigned long>& indices_cm, std::vector<Real>& masses_cm, - std::vector<unsigned long>& indices_atoms); - Real GetMinDistBetwCenterOfMassAndView(const mol::EntityView& view_cm, const mol::EntityView& view_atoms); - geom::Line3 GetODRLine(std::vector<unsigned long>& indices_ca); - geom::Plane GetODRPlane(std::vector<unsigned long>& indices_ca); - geom::Line3 GetODRLine(const mol::EntityView& view1); - geom::Plane GetODRPlane(const mol::EntityView& view1); - geom::Line3 FitCylinder(std::vector<unsigned long>& indices_ca); - geom::Line3 FitCylinder(const mol::EntityView& view1); - Real GetAlphaHelixContent(std::vector<unsigned long>& indices_ca, std::vector<unsigned long>& indices_c, - std::vector<unsigned long>& indices_o, std::vector<unsigned long>& indices_n); - Real GetAlphaHelixContent(const mol::EntityView& segment); -}; + std::vector<unsigned long>& indices2, std::vector<Real>& masses2) const; + + /*! + Returns the RMSD between the positions of the atoms whose indices are given in indices_sele + and the positions given in ref_pos + */ + Real GetRMSD(const std::vector<geom::Vec3>& ref_pos, + const std::vector<unsigned long>& indices_sele) const; + /*! + Returns the rmsd between two EntityViews. + + The reference positions are taken directly from the reference_view, + whereas they are taken from this CoordFrame for the sele_view + */ + Real GetRMSD(const mol::EntityView& reference_view, + const mol::EntityView& sele_view) const; + + //! Returns the minimal distance between two groups of atoms + /*! + with indices given by index_list1 and index_list2 + */ + Real GetMinDistance(std::vector<unsigned long>& index_list1, + std::vector<unsigned long>& index_list2) const; + + //! Returns the minimal distance between the atoms of two views (view1 and view2) + Real GetMinDistance(const mol::EntityView& view1, const mol::EntityView& view2) const; + + /*! + Returns the minimal distance between the center of mass of two groups of atoms + + atoms and their masses are defined by indices and masses for those atoms + */ + Real GetMinDistBetwCenterOfMassAndView(std::vector<unsigned long>& indices_cm, + std::vector<Real>& masses_cm, + std::vector<unsigned long>& indices_atoms) const; + //! Returns the minimal distance between the center of mass of two views + Real GetMinDistBetwCenterOfMassAndView(const mol::EntityView& view_cm, + const mol::EntityView& view_atoms) const; + + //! Returns the best fit line to atoms with indices in indices_ca + geom::Line3 GetODRLine(std::vector<unsigned long>& indices_ca) const; + + //! Returns the best fit line to atoms in the EntityView view1 + geom::Plane GetODRPlane(std::vector<unsigned long>& indices_ca) const; + + //! Returns the normal to the best fit plane to atoms with indices in indices_ca + geom::Line3 GetODRLine(const mol::EntityView& view1) const; + geom::Plane GetODRPlane(const mol::EntityView& view1) const; + + /*! + Returns a line which is the axis of a fitted cylinder to the atoms with indices given in indices_ca + It is assumed that we fit an alpha-helix and that the CA atoms are oredered sequentially + This is used for the initial guess of the helix axis + */ + geom::Line3 FitCylinder(std::vector<unsigned long>& indices_ca) const; + + //! see FitCylinder(std::vector<unsigned long>&) + geom::Line3 FitCylinder(const mol::EntityView& view1) const; + + /*! + Returns the percentage of residues in the EntityView (segment) that are in an alpha-helix + Each residue is assigned as being in an alpha-helix or not, based on and backbone torsion angles + and the hydrogen bonding (O-N) (this term is used only if the segment contains at least 8 residues + The entity view should be a single segment with no gaps and no missing N,CA,C,O backbone atoms + the first and last residues will not be asessed for helicity + */ + Real GetAlphaHelixContent(std::vector<unsigned long>& indices_ca, + std::vector<unsigned long>& indices_c, + std::vector<unsigned long>& indices_o, + std::vector<unsigned long>& indices_n) const; + + //! see above + Real GetAlphaHelixContent(const mol::EntityView& segment) const; +}; + + typedef boost::shared_ptr<CoordFrame> CoordFramePtr; + typedef std::vector<CoordFramePtr> CoordFrameList; + + // factory method + // create a frame from a Vec3List containing the positions of the atoms, optionally with unit cell + // TODO: why is this necessary? the ctor works fine + DLLEXPORT_OST_MOL CoordFrame CreateCoordFrame(const geom::Vec3List& atom_pos, + const geom::Vec3& cell_size=geom::Vec3(), + const geom::Vec3& cell_angles=geom::Vec3()); + + // these should really be either in the entity view interface or in mol/alg + + /*! + This function returns a vector containing the atom indices of the atoms in an EntityView; + it is used to accelerate the extraction of information from a trajectory + */ void GetIndices(const EntityView& sele, std::vector<unsigned long>& indices); + + /*! + This function returns a vector containing the atom masses of the atoms in an EntityView; + it is used together with GetIndices to accelerate the extraction of RMSD from a trajectory + */ void GetMasses(const EntityView& sele, std::vector<Real>& masses); - void GetIndicesAndMasses(const EntityView& sele, std::vector<unsigned long>& indices,std::vector<Real>& masses); + + //! conveniece for GetIndices and GetMasses in one call + void GetIndicesAndMasses(const EntityView& sele, + std::vector<unsigned long>& indices, + std::vector<Real>& masses); + + //! Writes the positions of all atoms in the EntityView into the provided vec3 list void GetPositions(const EntityView& sele, std::vector<geom::Vec3>& ref_pos); + + //! Writes the indices of all atoms in the EntityView into the provided list void GetCaIndices(const EntityView& segment, std::vector<unsigned long>& indices_ca); - void GetCaCONIndices(const EntityView& segment, std::vector<unsigned long>& indices_ca, std::vector<unsigned long>& indices_c, - std::vector<unsigned long>& indices_o, std::vector<unsigned long>& indices_n); -typedef boost::shared_ptr<CoordFrame> CoordFramePtr; -typedef std::vector<CoordFramePtr> CoordFrameList; + //! Writes the backbone indices of all residues in the EntityView into the provided list + void GetCaCONIndices(const EntityView& segment, + std::vector<unsigned long>& indices_ca, + std::vector<unsigned long>& indices_c, + std::vector<unsigned long>& indices_o, + std::vector<unsigned long>& indices_n); -// factory method -// create a frame froma Vec3List containing the positions of the atoms - DLLEXPORT_OST_MOL CoordFrame CreateCoordFrame(const geom::Vec3List& atom_pos); }}