Files
lammps/src/MOLFILE/molfile_interface.cpp
2021-10-07 14:37:37 -04:00

981 lines
28 KiB
C++

// clang-format off
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Axel Kohlmeyer (Temple)
------------------------------------------------------------------------- */
#include "molfile_interface.h"
#include "platform.h"
#include "tokenizer.h"
#include "utils.h"
#include "molfile_plugin.h"
#include <cstdio>
#include <cstring>
#include <cstdlib>
#if vmdplugin_ABIVERSION < 16
#error "unsupported VMD molfile plugin ABI version"
#endif
#define DEBUG 0
extern "C" {
typedef int (*initfunc)(void);
typedef int (*regfunc)(void *, vmdplugin_register_cb);
typedef int (*finifunc)(void);
typedef struct {
void *p;
const char *name;
} plugin_reginfo_t;
// callback function for plugin registration.
static int plugin_register_cb(void *v, vmdplugin_t *p)
{
plugin_reginfo_t *r = static_cast<plugin_reginfo_t *>(v);
// make sure we have the proper plugin type (native reader)
// for the desired file type (called "name" at this level)
if ((strcmp(MOLFILE_PLUGIN_TYPE,p->type) == 0)
&& (strcmp(r->name, p->name) == 0)) {
r->p = static_cast<void *>(p);
}
return 0;
}
/* periodic table of elements for translation of ordinal to atom type */
static const char *pte_label[] = {
"X", "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne",
"Na", "Mg", "Al", "Si", "P" , "S", "Cl", "Ar", "K", "Ca", "Sc",
"Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge",
"As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc",
"Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe",
"Cs", "Ba", "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb",
"Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os",
"Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr",
"Ra", "Ac", "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf",
"Es", "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt",
"Ds", "Rg"
};
static const int nr_pte_entries = sizeof(pte_label) / sizeof(char *);
/* corresponding table of masses. */
static const float pte_mass[] = {
/* X */ 0.00000, 1.00794, 4.00260, 6.941, 9.012182, 10.811,
/* C */ 12.0107, 14.0067, 15.9994, 18.9984032, 20.1797,
/* Na */ 22.989770, 24.3050, 26.981538, 28.0855, 30.973761,
/* S */ 32.065, 35.453, 39.948, 39.0983, 40.078, 44.955910,
/* Ti */ 47.867, 50.9415, 51.9961, 54.938049, 55.845, 58.9332,
/* Ni */ 58.6934, 63.546, 65.409, 69.723, 72.64, 74.92160,
/* Se */ 78.96, 79.904, 83.798, 85.4678, 87.62, 88.90585,
/* Zr */ 91.224, 92.90638, 95.94, 98.0, 101.07, 102.90550,
/* Pd */ 106.42, 107.8682, 112.411, 114.818, 118.710, 121.760,
/* Te */ 127.60, 126.90447, 131.293, 132.90545, 137.327,
/* La */ 138.9055, 140.116, 140.90765, 144.24, 145.0, 150.36,
/* Eu */ 151.964, 157.25, 158.92534, 162.500, 164.93032,
/* Er */ 167.259, 168.93421, 173.04, 174.967, 178.49, 180.9479,
/* W */ 183.84, 186.207, 190.23, 192.217, 195.078, 196.96655,
/* Hg */ 200.59, 204.3833, 207.2, 208.98038, 209.0, 210.0, 222.0,
/* Fr */ 223.0, 226.0, 227.0, 232.0381, 231.03588, 238.02891,
/* Np */ 237.0, 244.0, 243.0, 247.0, 247.0, 251.0, 252.0, 257.0,
/* Md */ 258.0, 259.0, 262.0, 261.0, 262.0, 266.0, 264.0, 269.0,
/* Mt */ 268.0, 271.0, 272.0
};
/*
* corresponding table of VDW radii.
* van der Waals radii are taken from A. Bondi,
* J. Phys. Chem., 68, 441 - 452, 1964,
* except the value for H, which is taken from R.S. Rowland & R. Taylor,
* J.Phys.Chem., 100, 7384 - 7391, 1996. Radii that are not available in
* either of these publications have RvdW = 2.00 \AA.
* The radii for Ions (Na, K, Cl, Ca, Mg, and Cs are based on the CHARMM27
* Rmin/2 parameters for (SOD, POT, CLA, CAL, MG, CES) by default.
*/
static const float pte_vdw_radius[] = {
/* X */ 1.5, 1.2, 1.4, 1.82, 2.0, 2.0,
/* C */ 1.7, 1.55, 1.52, 1.47, 1.54,
/* Na */ 1.36, 1.18, 2.0, 2.1, 1.8,
/* S */ 1.8, 2.27, 1.88, 1.76, 1.37, 2.0,
/* Ti */ 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
/* Ni */ 1.63, 1.4, 1.39, 1.07, 2.0, 1.85,
/* Se */ 1.9, 1.85, 2.02, 2.0, 2.0, 2.0,
/* Zr */ 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
/* Pd */ 1.63, 1.72, 1.58, 1.93, 2.17, 2.0,
/* Te */ 2.06, 1.98, 2.16, 2.1, 2.0,
/* La */ 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
/* Eu */ 2.0, 2.0, 2.0, 2.0, 2.0,
/* Er */ 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
/* W */ 2.0, 2.0, 2.0, 2.0, 1.72, 1.66,
/* Hg */ 1.55, 1.96, 2.02, 2.0, 2.0, 2.0, 2.0,
/* Fr */ 2.0, 2.0, 2.0, 2.0, 2.0, 1.86,
/* Np */ 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
/* Md */ 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
/* Mt */ 2.0, 2.0, 2.0
};
/* lookup functions */
static const char *get_pte_label(const int idx)
{
if ((idx < 1) || (idx >= nr_pte_entries)) return pte_label[0];
return pte_label[idx];
}
static float get_pte_mass(const int idx)
{
if ((idx < 1) || (idx >= nr_pte_entries)) return pte_mass[0];
return pte_mass[idx];
}
static float get_pte_vdw_radius(const int idx)
{
if ((idx < 1) || (idx >= nr_pte_entries)) return pte_vdw_radius[0];
#if 1
/* Replace with Hydrogen radius with an "all-atom" radius */
if (idx == 1)
return 1.0; /* H */
#else
/* Replace with old VMD atom radii values */
switch (idx) {
case 1: return 1.0; /* H */
case 6: return 1.5; /* C */
case 7: return 1.4; /* N */
case 8: return 1.3; /* O */
case 9: return 1.2; /* F */
case 15: return 1.5; /* P */
case 16: return 1.9; /* S */
}
#endif
return pte_vdw_radius[idx];
}
static int get_pte_idx_from_string(const char *label) {
int i, ind;
char atom[3];
if (label != nullptr) {
/* zap string */
atom[0] = atom[1] = atom[2] = '\0';
for (ind=0,i=0; (ind<2) && (label[i]!='\0'); i++) {
if (label[i] != ' ') {
atom[ind] = toupper(label[i]);
ind++;
}
}
if (ind < 1)
return 0; /* no non-whitespace characters */
for (i=0; i < nr_pte_entries; ++i) {
if ((toupper(pte_label[i][0]) == atom[0]) && (toupper(pte_label[i][1]) == atom[1]))
return i;
}
}
return 0;
}
} // end of extern "C" region
using namespace LAMMPS_NS;
// constructor.
MolfileInterface::MolfileInterface(const char *type, const int mode)
: _plugin(nullptr), _dso(nullptr), _ptr(nullptr), _info(nullptr), _natoms(0),
_mode(mode), _caps(M_NONE), _props(0)
{
_name = utils::strdup("none");
_type = utils::strdup(type);
}
// destructor.
MolfileInterface::~MolfileInterface()
{
forget_plugin();
if (_info) {
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
delete[] a;
_info = nullptr;
}
delete[] _name;
delete[] _type;
}
// register the best matching plugin in a given directory
int MolfileInterface::find_plugin(const char *pluginpath)
{
int retval = E_NONE;
if (pluginpath == nullptr) return E_DIR;
// search for suitable file names in provided path and try to inspect them
// only look at .so files, since this is what VMD uses on all platforms
for (const auto &dir : Tokenizer(pluginpath,":").as_vector()) {
for (const auto &filename : platform::list_directory(dir)) {
if (utils::strmatch(filename,"\\.so$")) {
int rv = load_plugin(platform::path_join(dir,filename).c_str());
if (rv > retval) retval = rv;
}
}
}
return retval;
}
// register the best matching plugin in a given directory
int MolfileInterface::load_plugin(const char *filename)
{
void *dso;
int retval = E_NONE;
// access shared object
dso = platform::dlopen(filename);
if (dso == nullptr)
return E_FILE;
// check for required plugin symbols
void *ifunc = platform::dlsym(dso,"vmdplugin_init");
void *rfunc = platform::dlsym(dso,"vmdplugin_register");
void *ffunc = platform::dlsym(dso,"vmdplugin_fini");
if (ifunc == nullptr || rfunc == nullptr || ffunc == nullptr) {
platform::dlclose(dso);
return E_SYMBOL;
}
// initialize plugin. skip plugin if it fails.
if (((initfunc)(ifunc))()) {
platform::dlclose(dso);
return E_SYMBOL;
}
// pre-register plugin.
// the callback will be called for each plugin in the DSO and
// check the file type. plugin->name will change if successful.
plugin_reginfo_t reginfo;
reginfo.p = nullptr;
reginfo.name=_type;
((regfunc)rfunc)(&reginfo, plugin_register_cb);
// make some checks to see if the plugin is suitable or not.
molfile_plugin_t *plugin = static_cast<molfile_plugin_t *>(reginfo.p);
// if the callback found a matching plugin and copied the struct,
// its name element will point to a different location now.
if (plugin == nullptr) {
retval = E_TYPE;
// check if the ABI matches the one used to compile this code
} else if (plugin->abiversion != vmdplugin_ABIVERSION) {
retval = E_ABI;
// check if (basic) reading is supported
} else if ((_mode & M_READ) &&
( (plugin->open_file_read == nullptr) ||
(plugin->read_next_timestep == nullptr) ||
(plugin->close_file_read == nullptr) )) {
retval = E_MODE;
// check if (basic) writing is supported
} else if ( (_mode & M_WRITE) &&
( (plugin->open_file_write == nullptr) ||
(plugin->write_timestep == nullptr) ||
(plugin->close_file_write == nullptr) )) {
retval = E_MODE;
// make some additional check, if we
// already have a plugin registered.
// NOTE: this has to come last.
} else if (_dso && _plugin) {
molfile_plugin_t *p;
p = static_cast<molfile_plugin_t *>(_plugin);
// check if the new plugin is of a newer major version
if (p->majorv > plugin->majorv) {
retval = E_VERSION;
// check if the new plugin is of a newer minor version
} else if ( (p->majorv == plugin->majorv) &&
(p->minorv >= plugin->minorv)) {
retval = E_VERSION;
}
}
// bingo! this one is a keeper.
if (retval == E_NONE) {
// make sure any existing plugin is wiped out
forget_plugin();
delete[] _name;
_name = utils::strdup(fmt::format("{} v{}.{} by {}", plugin->prettyname,
plugin->majorv, plugin->minorv, plugin->author));
// determine plugin capabilities
_caps = M_NONE;
if (plugin->read_next_timestep) _caps |= M_READ;
if (plugin->write_timestep) _caps |= M_WRITE;
#if vmdplugin_ABIVERSION > 10
// required to tell if velocities are present
if (plugin->read_timestep_metadata) _caps |= M_RVELS;
// we can always offer velocities. we may not know if
// they will be written by the plugin though.
if (plugin->write_timestep) _caps |= M_WVELS;
#endif
if (plugin->read_structure) _caps |= M_RSTRUCT;
if (plugin->write_structure) _caps |= M_WSTRUCT;
if (plugin->read_bonds) _caps |= M_RBONDS;
if (plugin->write_bonds) _caps |= M_WBONDS;
if (plugin->read_angles) _caps |= M_RANGLES;
if (plugin->write_angles) _caps |= M_WANGLES;
if (plugin->read_volumetric_data) _caps |= M_RVOL;
if (plugin->write_volumetric_data) _caps |= M_WVOL;
if (_mode & M_WRITE) {
_mode |= (_caps & M_WSTRUCT);
_mode |= (_caps & M_WVELS);
} else if (_mode & M_READ) {
_mode |= (_caps & M_RSTRUCT);
_mode |= (_caps & M_RVELS);
}
_plugin = plugin;
_dso = dso;
return E_MATCH;
}
// better luck next time. clean up and return.
platform::dlclose(dso);
return retval;
}
// deregister a plugin and close or reset all associated objects.
void MolfileInterface::forget_plugin()
{
if (_ptr)
close();
if (_plugin)
_plugin = nullptr;
if (_dso) {
void *ffunc = platform::dlsym(_dso,"vmdplugin_fini");
if (ffunc)
((finifunc)ffunc)();
platform::dlclose(_dso);
}
_dso = nullptr;
delete[] _name;
_name = new char[5];
strcpy(_name,"none");
_caps = M_NONE;
}
// open file for reading or writing
int MolfileInterface::open(const char *name, int *natoms)
{
if (!_plugin || !_dso || !natoms)
return E_FILE;
molfile_plugin_t *p = static_cast<molfile_plugin_t *>(_plugin);
if (_mode & M_WRITE)
_ptr = p->open_file_write(name,_type,*natoms);
else if (_mode & M_READ)
_ptr = p->open_file_read(name,_type,natoms);
if (_ptr == nullptr)
return E_FILE;
_natoms = *natoms;
// we need to deal with structure information,
// so we allocate and initialize storage for it.
if (_mode & (M_RSTRUCT|M_WSTRUCT)) {
molfile_atom_t *a = new molfile_atom_t[_natoms];
_info = a;
memset(_info,0,_natoms*sizeof(molfile_atom_t));
for (int i=0; i < _natoms; ++i) {
a[i].name[0] = 'X';
a[i].type[0] = a[i].resname[0] = a[i].segid[0] = 'U';
a[i].type[1] = a[i].resname[1] = a[i].segid[1] = 'N';
a[i].type[2] = a[i].resname[2] = a[i].segid[2] = 'K';
a[i].chain[0] = 'X';
}
}
return E_NONE;
}
// get of set atom structure information
int MolfileInterface::structure()
{
if (!_plugin || !_dso)
return E_FILE;
molfile_plugin_t *p = static_cast<molfile_plugin_t *>(_plugin);
int optflags = MOLFILE_NOOPTIONS;
if (_mode & M_WSTRUCT) {
optflags |= (_props & P_BFAC) ? MOLFILE_BFACTOR : 0;
optflags |= (_props & P_OCCP) ? MOLFILE_OCCUPANCY : 0;
optflags |= (_props & P_MASS) ? MOLFILE_MASS : 0;
optflags |= (_props & P_CHRG) ? MOLFILE_CHARGE : 0;
optflags |= (_props & P_RADS) ? MOLFILE_RADIUS : 0;
optflags |= (_props & P_ATMN) ? MOLFILE_ATOMICNUMBER : 0;
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
p->write_structure(_ptr,optflags,a);
} else if (_mode & M_RSTRUCT) {
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
p->read_structure(_ptr,&optflags,a);
// mandatory properties
_props = P_NAME|P_TYPE|P_RESN|P_RESI|P_SEGN|P_CHAI;
// optional properties
_props |= (optflags & MOLFILE_BFACTOR) ? P_BFAC : 0;
_props |= (optflags & MOLFILE_OCCUPANCY) ? P_OCCP : 0;
_props |= (optflags & MOLFILE_MASS) ? P_MASS : 0;
_props |= (optflags & MOLFILE_CHARGE) ? P_CHRG : 0;
_props |= (optflags & MOLFILE_RADIUS) ? P_RADS : 0;
_props |= (optflags & MOLFILE_ATOMICNUMBER) ? P_ATMN : 0;
}
return 0;
}
// safely close file
int MolfileInterface::close()
{
if (!_plugin || !_dso || !_ptr)
return E_FILE;
molfile_plugin_t *p = static_cast<molfile_plugin_t *>(_plugin);
if (_mode & M_WRITE) {
p->close_file_write(_ptr);
} else if (_mode & M_READ) {
p->close_file_read(_ptr);
}
if (_info) {
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
delete[] a;
_info = nullptr;
}
_ptr = nullptr;
_natoms = 0;
return E_NONE;
}
// read or write timestep
int MolfileInterface::timestep(float *coords, float *vels,
float *cell, double *simtime)
{
if (!_plugin || !_dso || !_ptr)
return 1;
molfile_plugin_t *p = static_cast<molfile_plugin_t *>(_plugin);
molfile_timestep_t *t = new molfile_timestep_t;
int rv;
if (_mode & M_WRITE) {
t->coords = coords;
t->velocities = vels;
if (cell != nullptr) {
t->A = cell[0];
t->B = cell[1];
t->C = cell[2];
t->alpha = cell[3];
t->beta = cell[4];
t->gamma = cell[5];
} else {
t->A = 0.0f;
t->B = 0.0f;
t->C = 0.0f;
t->alpha = 90.0f;
t->beta = 90.0f;
t->gamma = 90.0f;
}
if (simtime)
t->physical_time = *simtime;
else
t->physical_time = 0.0;
rv = p->write_timestep(_ptr,t);
} else {
// no coordinate storage => skip step
if (coords == nullptr) {
rv = p->read_next_timestep(_ptr, _natoms, nullptr);
} else {
t->coords = coords;
t->velocities = vels;
t->A = 0.0f;
t->B = 0.0f;
t->C = 0.0f;
t->alpha = 90.0f;
t->beta = 90.0f;
t->gamma = 90.0f;
t->physical_time = 0.0;
rv = p->read_next_timestep(_ptr, _natoms, t);
if (cell != nullptr) {
cell[0] = t->A;
cell[1] = t->B;
cell[2] = t->C;
cell[3] = t->alpha;
cell[4] = t->beta;
cell[5] = t->gamma;
}
if (simtime)
*simtime = t->physical_time;
}
if (rv == MOLFILE_EOF) {
delete t;
return 1;
}
}
delete t;
return 0;
}
// functions to read properties from molfile structure
#define PROPUPDATE(PROP,ENTRY,VAL) \
if (propid == PROP) { VAL = a.ENTRY; }
#define PROPSTRCPY(PROP,ENTRY,VAL) \
if (propid == PROP) { strcpy(VAL,a.ENTRY); }
// single precision floating point props
static float read_float_property(molfile_atom_t &a, const int propid)
{
float prop = 0.0f;
int iprop = 0;
PROPUPDATE(MolfileInterface::P_OCCP,occupancy,prop);
PROPUPDATE(MolfileInterface::P_BFAC,bfactor,prop);
PROPUPDATE(MolfileInterface::P_MASS,mass,prop);
PROPUPDATE(MolfileInterface::P_CHRG,charge,prop);
PROPUPDATE(MolfileInterface::P_RADS,radius,prop);
PROPUPDATE((MolfileInterface::P_ATMN|MolfileInterface::P_MASS),
atomicnumber,iprop);
PROPUPDATE((MolfileInterface::P_ATMN|MolfileInterface::P_RADS),
atomicnumber,iprop);
if (propid & MolfileInterface::P_ATMN) {
if (propid & MolfileInterface::P_MASS)
prop = get_pte_mass(iprop);
if (propid & MolfileInterface::P_RADS)
prop = get_pte_vdw_radius(iprop);
}
return prop;
}
// integer and derived props
static int read_int_property(molfile_atom_t &a, const int propid)
{
int prop = 0;
const char * sprop;
PROPUPDATE(MolfileInterface::P_RESI,resid,prop);
PROPUPDATE(MolfileInterface::P_ATMN,atomicnumber,prop);
PROPUPDATE((MolfileInterface::P_ATMN|MolfileInterface::P_NAME),
name,sprop);
PROPUPDATE((MolfileInterface::P_ATMN|MolfileInterface::P_TYPE),
type,sprop);
if (propid & MolfileInterface::P_ATMN) {
if (propid & (MolfileInterface::P_NAME|MolfileInterface::P_TYPE))
prop = get_pte_idx_from_string(sprop);
}
return prop;
}
// string and derived props
static const char *read_string_property(molfile_atom_t &a,
const int propid)
{
const char *prop = nullptr;
int iprop = 0;
PROPUPDATE(MolfileInterface::P_NAME,name,prop);
PROPUPDATE(MolfileInterface::P_TYPE,type,prop);
PROPUPDATE(MolfileInterface::P_RESN,resname,prop);
PROPUPDATE(MolfileInterface::P_SEGN,segid,prop);
PROPUPDATE((MolfileInterface::P_ATMN|MolfileInterface::P_NAME),
atomicnumber,iprop);
PROPUPDATE((MolfileInterface::P_ATMN|MolfileInterface::P_TYPE),
atomicnumber,iprop);
if (propid & MolfileInterface::P_ATMN) {
if (propid & (MolfileInterface::P_NAME|MolfileInterface::P_TYPE))
prop = get_pte_label(iprop);
}
return prop;
}
#undef PROPUPDATE
#undef PROPSTRCPY
// functions to store properties into molfile structure
#define PROPUPDATE(PROP,ENTRY,VAL) \
if ((propid & PROP) == PROP) { a.ENTRY = VAL; plist |= PROP; }
#define PROPSTRCPY(PROP,ENTRY,VAL) \
if ((propid & PROP) == PROP) { strcpy(a.ENTRY,VAL); plist |= PROP; }
// floating point props
static int write_atom_property(molfile_atom_t &a,
const int propid,
const float prop)
{
int plist = MolfileInterface::P_NONE;
PROPUPDATE(MolfileInterface::P_OCCP,occupancy,prop);
PROPUPDATE(MolfileInterface::P_BFAC,bfactor,prop);
PROPUPDATE(MolfileInterface::P_MASS,mass,prop);
PROPUPDATE(MolfileInterface::P_CHRG,charge,prop);
PROPUPDATE(MolfileInterface::P_RADS,radius,prop);
return plist;
}
// double precision floating point props
static int write_atom_property(molfile_atom_t &a,
const int propid,
const double prop)
{
return write_atom_property(a,propid,static_cast<float>(prop));
}
// integer and derived props
static int write_atom_property(molfile_atom_t &a,
const int propid,
const int prop)
{
int plist = MolfileInterface::P_NONE;
PROPUPDATE(MolfileInterface::P_RESI,resid,prop);
PROPUPDATE(MolfileInterface::P_ATMN,atomicnumber,prop);
PROPUPDATE((MolfileInterface::P_ATMN|MolfileInterface::P_MASS),
mass,get_pte_mass(prop));
PROPSTRCPY((MolfileInterface::P_ATMN|MolfileInterface::P_NAME),
name,get_pte_label(prop));
PROPSTRCPY((MolfileInterface::P_ATMN|MolfileInterface::P_TYPE),
type,get_pte_label(prop));
return plist;
}
// integer and derived props
static int write_atom_property(molfile_atom_t &a,
const int propid,
const char *prop)
{
int plist = MolfileInterface::P_NONE;
PROPSTRCPY(MolfileInterface::P_NAME,name,prop);
PROPSTRCPY(MolfileInterface::P_TYPE,type,prop);
PROPSTRCPY(MolfileInterface::P_RESN,resname,prop);
PROPSTRCPY(MolfileInterface::P_SEGN,segid,prop);
return plist;
}
#undef PROPUPDATE
#undef PROPSTRCPY
// set/get atom floating point property
int MolfileInterface::property(int propid, int idx, float *prop)
{
if ((_info == nullptr) || (prop == nullptr) || (idx < 0) || (idx >= _natoms))
return P_NONE;
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
if (_mode & M_WSTRUCT)
_props |= write_atom_property(a[idx], propid, *prop);
if (_mode & M_RSTRUCT)
*prop = read_float_property(a[idx], propid);
return _props;
}
// set/get per type floating point property
int MolfileInterface::property(int propid, int *types, float *prop)
{
if ((_info == nullptr) || (types == nullptr) || (prop == nullptr))
return P_NONE;
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
if (_mode & M_WSTRUCT) {
for (int i=0; i < _natoms; ++i)
_props |= write_atom_property(a[i], propid, prop[types[i]]);
}
// useless for reading.
if (_mode & M_RSTRUCT)
return P_NONE;
return _props;
}
// set/get per atom floating point property
int MolfileInterface::property(int propid, float *prop)
{
if ((_info == nullptr) || (prop == nullptr))
return P_NONE;
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
if (_mode & M_WSTRUCT) {
for (int i=0; i < _natoms; ++i)
_props |= write_atom_property(a[i], propid, prop[i]);
}
if (_mode & M_RSTRUCT) {
for (int i=0; i < _natoms; ++i)
prop[i] = read_float_property(a[i], propid);
}
return _props;
}
// set/get atom floating point property
int MolfileInterface::property(int propid, int idx, double *prop)
{
if ((_info == nullptr) || (prop == nullptr) || (idx < 0) || (idx >= _natoms))
return P_NONE;
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
if (_mode & M_WSTRUCT)
return write_atom_property(a[idx], propid, *prop);
if (_mode & M_RSTRUCT)
*prop = static_cast<double>(read_float_property(a[idx], propid));
return _props;
}
// set/get per type floating point property
int MolfileInterface::property(int propid, int *types, double *prop)
{
if ((_info == nullptr) || (types == nullptr) || (prop == nullptr))
return P_NONE;
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
if (_mode & M_WSTRUCT) {
for (int i=0; i < _natoms; ++i)
_props |= write_atom_property(a[i], propid, prop[types[i]]);
}
// useless for reading
if (_mode & M_RSTRUCT)
return P_NONE;
return _props;
}
// set/get per atom floating point property
int MolfileInterface::property(int propid, double *prop)
{
if ((_info == nullptr) || (prop == nullptr))
return P_NONE;
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
if (_mode & M_WSTRUCT) {
for (int i=0; i < _natoms; ++i)
_props |= write_atom_property(a[i], propid, prop[i]);
}
if (_mode & M_RSTRUCT) {
for (int i=0; i < _natoms; ++i)
prop[i] = static_cast<double>(read_float_property(a[i], propid));
}
return _props;
}
#define INT_TO_STRING_BODY(IDX) \
buf[15] = 0; \
if (propid & P_NAME) \
_props |= write_atom_property(a[IDX],P_NAME,buf); \
if (propid & P_TYPE) \
_props |= write_atom_property(a[IDX],P_TYPE,buf); \
buf[7] = 0; \
if (propid & P_RESN) \
_props |= write_atom_property(a[IDX],P_RESN,buf); \
if (propid & P_SEGN) \
_props |= write_atom_property(a[IDX],P_SEGN,buf); \
buf[1] = 0; \
if (propid & P_CHAI) \
_props |= write_atom_property(a[IDX],P_CHAI,buf)
// set/get atom integer property
int MolfileInterface::property(int propid, int idx, int *prop)
{
if ((_info == nullptr) || (prop == nullptr) || (idx < 0) || (idx >= _natoms))
return P_NONE;
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
if (_mode & M_WSTRUCT) {
char buf[64];
_props |= write_atom_property(a[idx], propid, *prop);
if (propid & (P_NAME|P_TYPE|P_RESN|P_SEGN|P_CHAI)) {
sprintf(buf,"%d",*prop);
INT_TO_STRING_BODY(idx);
}
}
if (_mode & M_RSTRUCT)
*prop = read_int_property(a[idx], propid);
return _props;
}
// set/get per type integer property
int MolfileInterface::property(int propid, int *types, int *prop)
{
if ((_info == nullptr) || (types == nullptr) || (prop == nullptr))
return P_NONE;
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
if (_mode & M_WSTRUCT) {
char buf[64];
for (int i=0; i < _natoms; ++i)
_props |= write_atom_property(a[i], propid, prop[types[i]]);
if (propid & (P_NAME|P_TYPE|P_RESN|P_SEGN|P_CHAI)) {
for (int i=0; i < _natoms; ++i) {
sprintf(buf,"%d",prop[types[i]]);
INT_TO_STRING_BODY(i);
}
}
}
// useless when reading
if (_mode & M_RSTRUCT)
return P_NONE;
return _props;
}
// set/get per atom integer property
int MolfileInterface::property(int propid, int *prop)
{
if ((_info == nullptr) || (prop == nullptr))
return P_NONE;
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
if (_mode & M_WSTRUCT) {
char buf[64];
for (int i=0; i < _natoms; ++i)
_props |= write_atom_property(a[i],propid,prop[i]);
if (propid & (P_NAME|P_TYPE|P_RESN|P_SEGN|P_CHAI)) {
for (int i=0; i < _natoms; ++i) {
sprintf(buf,"%d",prop[i]);
INT_TO_STRING_BODY(i);
}
}
}
if (_mode & M_RSTRUCT) {
for (int i=0; i < _natoms; ++i)
prop[i] = read_int_property(a[i], propid);
}
return _props;
}
#undef INT_TO_STRING_BODY
// set/get atom string property
int MolfileInterface::property(int propid, int idx, char *prop)
{
if ((_info == nullptr) || (prop == nullptr) || (idx < 0) || (idx >= _natoms))
return P_NONE;
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
if (_mode & M_WSTRUCT) {
_props |= write_atom_property(a[idx], propid, prop);
}
if (_mode & M_RSTRUCT)
strcpy(prop,read_string_property(a[idx], propid));
return _props;
}
// set/get per type string property
int MolfileInterface::property(int propid, int *types, char **prop)
{
if ((_info == nullptr) || (types == nullptr) || (prop == nullptr))
return P_NONE;
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
if (_mode & M_WSTRUCT) {
for (int i=0; i < _natoms; ++i) {
_props |= write_atom_property(a[i], propid, prop[types[i]]);
}
}
// useless when reading
if (_mode & M_RSTRUCT)
return P_NONE;
return _props;
}
// set/get per atom string property
int MolfileInterface::property(int propid, char **prop)
{
if ((_info == nullptr) || (prop == nullptr))
return P_NONE;
molfile_atom_t *a = static_cast<molfile_atom_t *>(_info);
if (_mode & M_WSTRUCT) {
for (int i=0; i < _natoms; ++i) {
_props |= write_atom_property(a[i], propid, prop[i]);
}
}
// not supported right now. XXX: should we use strdup() here?
if (_mode & M_RSTRUCT)
return P_NONE;
return _props;
}