/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 2011-2023 The plumed team
(see the PEOPLE file at the root of the distribution for a list of names)
See http://www.plumed.org for more information.
This file is part of plumed, version 2.
plumed 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 of the License, or
(at your option) any later version.
plumed 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 plumed. If not, see .
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
#include "core/ActionWithArguments.h"
#include "core/ActionWithValue.h"
#include "core/ActionAtomistic.h"
#include "core/ActionPilot.h"
#include "core/ActionRegister.h"
#include "core/PlumedMain.h"
#include "tools/OFile.h"
#include "tools/h36.h"
namespace PLMD {
namespace generic {
//+PLUMEDOC PRINTANALYSIS DUMPPDB
/*
Output PDB file.
\par Examples
*/
//+ENDPLUMEDOC
class DumpPDB :
public ActionWithArguments,
public ActionPilot {
std::string fmt;
std::string file;
std::string description;
std::vector pdb_resid_indices;
std::vector beta, occupancy;
std::vector argnames;
std::vector pdb_atom_indices;
void buildArgnames();
void printAtom( OFile& opdbf, const unsigned& anum, const unsigned& rnum, const Vector& pos, const double& m, const double& q ) const ;
public:
static void registerKeywords( Keywords& keys );
explicit DumpPDB(const ActionOptions&);
void calculate() override {}
void apply() override {}
void update() override ;
};
PLUMED_REGISTER_ACTION(DumpPDB,"DUMPPDB")
void DumpPDB::registerKeywords( Keywords& keys ) {
Action::registerKeywords( keys );
ActionPilot::registerKeywords( keys );
ActionWithArguments::registerKeywords( keys );
keys.use("ARG");
keys.add("optional","ATOMS","value containing positions of atoms that should be output");
keys.add("compulsory","STRIDE","0","the frequency with which the atoms should be output");
keys.add("compulsory","FILE","the name of the file on which to output these quantities");
keys.add("compulsory","FMT","%f","the format that should be used to output real numbers");
keys.add("compulsory","OCCUPANCY","1.0","vector of values to output in the occupancy column of the pdb file");
keys.add("compulsory","BETA","1.0","vector of values to output in the beta column of the pdb file");
keys.add("optional","DESCRIPTION","the title to use for your PDB output");
keys.add("optional","ATOM_INDICES","the indices of the atoms in your PDB output");
keys.add("optional","RESIDUE_INDICES","the indices of the residues in your PDB output");
keys.add("optional","ARG_NAMES","the names of the arguments that are being output");
}
DumpPDB::DumpPDB(const ActionOptions&ao):
Action(ao),
ActionWithArguments(ao),
ActionPilot(ao) {
parse("FILE",file);
if(file.length()==0) {
error("name out output file was not specified");
}
std::vector atoms;
parseVector("ATOMS",atoms);
if( atoms.size()>0 ) {
std::vector atom_args;
interpretArgumentList( atoms, plumed.getActionSet(), this, atom_args );
if( atom_args.size()!=1 ) {
error("only one action should appear in input to atom args");
}
std::vector args( getArguments() );
args.push_back( atom_args[0] );
requestArguments( args );
std::vector indices;
parseVector("ATOM_INDICES",indices);
std::vector xvals,yvals,zvals,masv,chargev;
ActionAtomistic::getAtomValuesFromPlumedObject(plumed,xvals,yvals,zvals,masv,chargev);
ActionAtomistic::interpretAtomList( indices, xvals, this, pdb_atom_indices );
log.printf(" printing atoms : ");
for(unsigned i=0; igetShape()[1]/3 ) {
error("mismatch between size of matrix containing positions and vector of atom indices");
}
beta.resize( atom_args[0]->getShape()[1]/3 );
occupancy.resize( atom_args[0]->getShape()[1]/3 );
parseVector("OCCUPANCY", occupancy );
parseVector("BETA", beta );
parseVector("RESIDUE_INDICES",pdb_resid_indices);
if( pdb_resid_indices.size()==0 ) {
pdb_resid_indices.resize( pdb_atom_indices.size() );
for(unsigned i=0; igetRank()==0 || getPntrToArgument(0)->hasDerivatives() ) {
error("argument for printing of PDB should be vector or matrix");
}
unsigned nv=getPntrToArgument(0)->getShape()[0];
for(unsigned i=0; igetRank()==0 || getPntrToArgument(i)->hasDerivatives() ) {
error("argument for printing of PDB should be vector or matrix");
}
if( getPntrToArgument(i)->getShape()[0]!=nv ) {
error("for printing to pdb files all arguments must have same number of values");
}
}
}
void DumpPDB::printAtom( OFile& opdbf, const unsigned& anum, const unsigned& rnum, const Vector& pos, const double& m, const double& q ) const {
if( rnum>999 ) {
plumed_merror("atom number too large to be used as residue number");
}
std::array at;
const char* msg = h36::hy36encode(5,anum,&at[0]);
plumed_assert(msg==nullptr) << msg;
at[5]=0;
double lunits = plumed.getUnits().getLength()/0.1;
opdbf.printf("ATOM %s X RES %4u %8.3f%8.3f%8.3f%6.2f%6.2f\n",
&at[0], rnum, lunits*pos[0], lunits*pos[1], lunits*pos[2], m, q );
}
void DumpPDB::buildArgnames() {
unsigned nargs = getNumberOfArguments();
if( pdb_atom_indices.size()>0 ) {
nargs = nargs - 1;
}
if( nargs<0 ) {
return;
}
argnames.resize(0);
unsigned nvals = getPntrToArgument(0)->getShape()[0];
if( getPntrToArgument(0)->getRank()==2 ) {
nvals = getPntrToArgument(0)->getShape()[0];
}
for(unsigned i=0; igetShape()[0]!=nvals ) {
error("all arguments should have same number of values");
}
if( getPntrToArgument(i)->getRank()==1 ) {
argnames.push_back( getPntrToArgument(i)->getName() );
} else if( getPntrToArgument(i)->getRank()==2 ) {
(getPntrToArgument(i)->getPntrToAction())->getMatrixColumnTitles( argnames );
}
getPntrToArgument(i)->buildDataStore();
}
}
void DumpPDB::update() {
OFile opdbf;
opdbf.link(*this);
opdbf.setBackupString("analysis");
opdbf.open( file );
std::size_t psign=fmt.find("%");
plumed_assert( psign!=std::string::npos );
std::string descr2="%s=%-" + fmt.substr(psign+1) + " ";
unsigned totargs = 0;
unsigned nvals = getPntrToArgument(0)->getShape()[0];
for(unsigned i=0; igetShape()[0]!=nvals ) {
error("all arguments should have same number of values");
}
if( getPntrToArgument(i)->getRank()==1 ) {
totargs += 1;
} else if( getPntrToArgument(i)->getRank()==2 ) {
totargs += getPntrToArgument(i)->getShape()[1];
}
}
if( totargs!=argnames.size() ) {
buildArgnames();
}
if( description.length()>0 ) {
opdbf.printf("# %s AT STEP %lld TIME %f \n", description.c_str(), getStep(), getTime() );
}
unsigned nargs = getNumberOfArguments(), atomarg=0;
if( pdb_atom_indices.size()>0 ) {
if( nargs>1 ) {
atomarg = nargs - 1;
nargs = nargs-1;
} else {
nargs = 0;
}
}
for(unsigned i=0; igetRank()==1 ) {
opdbf.printf( descr2.c_str(), argnames[n].c_str(), thisarg->get(i) );
n++;
} else if( thisarg->getRank()==2 ) {
unsigned ncols = thisarg->getShape()[1];
for(unsigned k=0; kget(i*ncols+k) );
n++;
}
}
opdbf.printf("\n");
}
if( pdb_atom_indices.size()>0 ) {
unsigned npos = pdb_atom_indices.size();
Vector pos;
for(unsigned k=0; kget(npos*(3*i+0) + k);
pos[1]=getPntrToArgument(atomarg)->get(npos*(3*i+1) + k);
pos[2]=getPntrToArgument(atomarg)->get(npos*(3*i+2) + k);
printAtom( opdbf, pdb_atom_indices[k].serial(), pdb_resid_indices[k], pos, occupancy[k], beta[k] );
}
}
opdbf.printf("END\n");
}
opdbf.close();
}
}
}