Commit 2c31d23f authored by Berk Onat's avatar Berk Onat

Adding functions for structure and trajectory writing through molfile.save

parent cf9a67ca
......@@ -20,7 +20,7 @@
%{
/* Python SWIG interface to libpymolfile
Copyright (c) 2017 Berk Onat <b.onat@warwick.ac.uk>
Copyright (c) 2018 Berk Onat <b.onat@warwick.ac.uk>
Published with UIUC LICENSE
*/
#define SWIG_FILE_WITH_INIT
......@@ -79,7 +79,7 @@ extern PyObject * molfile_plugin_info(PyObject* molcapsule, int plugin_no);
%inline %{
PyObject * my_open_file_read(PyObject* molcapsule, char* fname, char* ftype, int natoms) {
if (PyType_Ready(&MolObjectType) < 0)
return NULL;
Py_RETURN_NONE;
PyTypeObject *type = &MolObjectType;
MolObject *plugin_c;
molfile_plugin_t* plugin = (molfile_plugin_t*) PyMolfileCapsule_AsVoidPtr(molcapsule);
......@@ -97,6 +97,82 @@ PyObject * my_open_file_read(PyObject* molcapsule, char* fname, char* ftype, int
}
%}
%feature("autodoc", "0") my_open_file_write;
%rename (open_file_write) my_open_file_write;
%exception my_open_file_write {
$action
if (PyErr_Occurred()) SWIG_fail;
}
%inline %{
PyObject * my_open_file_write(PyObject* molcapsule, char* fname, char* ftype, int natoms) {
if (PyType_Ready(&MolObjectType) < 0)
Py_RETURN_NONE;
if(natoms < 1)
Py_RETURN_NONE;
PyTypeObject *type = &MolObjectType;
MolObject *plugin_c;
molfile_plugin_t* plugin = (molfile_plugin_t*) PyMolfileCapsule_AsVoidPtr(molcapsule);
plugin_c = (MolObject *)type->tp_alloc(type, 0);
plugin_c->plugin = molcapsule;
void *file_handle = plugin->open_file_write(fname, ftype, natoms);
plugin_c->file_handle = PyMolfileCapsule_FromVoidPtr(file_handle, del_molfile_file_handle);
if (!plugin_c->file_handle) {
Py_RETURN_NONE;
} else {
plugin_c->natoms = natoms;
return (PyObject *)plugin_c;
}
}
%}
/*
%feature("autodoc", "0") my_set_file_write_stdout;
%rename (set_file_write_stdout) my_set_file_write_stdout;
%exception my_set_file_write_stdout {
$action
if (PyErr_Occurred()) SWIG_fail;
}
%inline %{
PyObject * my_set_file_write_stdout(PyObject* molpack) {
MolObject* plugin_handle = (MolObject*) molpack;
PyObject* filecapsule = plugin_handle->file_handle;
void *file_handle = (void*) PyMolfileCapsule_AsVoidPtr(filecapsule);
if(file_handle->fd){
fclose(file_handle->fd);
file_handle->fd = stdout;
}
else if(file_handle->fp){
fclose(file_handle->fp);
file_handle->fp = stdout;
}
else if(file_handle->file){
fclose(file_handle->file);
file_handle->file = stdout;
}
else if(file_handle->mf){
fclose(file_handle->mf);
file_handle->mf = stdout;
}
else if(file_handle->writer){
if(file_handle->writer->fd){
fclose(file_handle->writer->fd);
file_handle->writer->fd = stdout;
}
}
else (file_handle){
fclose(file_handle);
file_handle = stdout;
}
plugin_handle->file_handle = PyMolfileCapsule_FromVoidPtr(file_handle, del_molfile_file_handle);
if (!plugin_c->file_handle) {
Py_RETURN_NONE;
} else {
return (PyObject *)plugin_handle;
}
}
%}
*/
%feature("autodoc", "0") my_close_file_read;
%rename (close_file_read) my_close_file_read;
%exception my_close_file_read {
......@@ -115,18 +191,49 @@ PyObject * my_close_file_read(PyObject* molpack) {
}
%}
%feature("autodoc", "0") my_close_file_write;
%rename (close_file_write) my_close_file_write;
%exception my_close_file_write {
$action
if (PyErr_Occurred()) SWIG_fail;
}
%inline %{
PyObject * my_close_file_write(PyObject* molpack) {
MolObject* plugin_handle = (MolObject*) molpack;
PyObject* plugincapsule = plugin_handle->plugin;
PyObject* filecapsule = plugin_handle->file_handle;
molfile_plugin_t* plugin = (molfile_plugin_t*) PyMolfileCapsule_AsVoidPtr(plugincapsule);
void *file_handle = (void*) PyMolfileCapsule_AsVoidPtr(filecapsule);
plugin->close_file_write(file_handle);
Py_RETURN_TRUE;
}
%}
%feature("autodoc", "0") read_fill_structure;
extern PyObject * read_fill_structure(PyObject* molpack, PyObject* prototype);
%feature("autodoc", "0") write_fill_structure;
extern PyObject * write_fill_structure(PyObject* molpack, PyObject* molarray);
%feature("autodoc", "0") read_fill_bonds;
extern PyObject * read_fill_bonds(PyObject* molpack);
%feature("autodoc", "0") write_fill_bonds;
extern PyObject * write_fill_bonds(PyObject* molpack, PyObject* moldict);
%feature("autodoc", "0") read_fill_angles;
extern PyObject * read_fill_angles(PyObject* molpack);
%feature("autodoc", "0") write_fill_angles;
extern PyObject * write_fill_angles(PyObject* molpack, PyObject* moldict);
%feature("autodoc", "0") read_fill_next_timestep;
extern PyObject * read_fill_next_timestep(PyObject* molpack);
%feature("autodoc", "0") write_fill_timestep;
extern PyObject * write_fill_timestep(PyObject* molpack, PyObject* moldict);
%feature("autodoc", "0") are_plugins_same;
PyObject* are_plugins_same(PyObject* molpack_a, PyObject* molpack_b);
......
......@@ -209,6 +209,62 @@ PyObject * molfile_plugin_info(PyObject* molcapsule, int plugin_no) {
return tuple;
}
PyObject* write_fill_structure(PyObject* molpack, PyObject* molarray)
{
//Py_Initialize();
initNumpyArray();
int options = 0;
options = MOLFILE_INSERTION | MOLFILE_OCCUPANCY | MOLFILE_BFACTOR |
MOLFILE_ALTLOC | MOLFILE_ATOMICNUMBER | MOLFILE_BONDSSPECIAL |
MOLFILE_MASS | MOLFILE_CHARGE;
molfile_plugin_t* plugin;
void* file_handle;
molfile_atom_t* data;
int numatoms, status;
// Access plugin_handle values
MolObject* plugin_handle = (MolObject*) molpack;
if (plugin_handle->plugin) {
plugin = (molfile_plugin_t*) PyMolfileCapsule_AsVoidPtr(plugin_handle->plugin);
} else {
PyErr_Format(PyExc_IOError, "molfile plugin is not active.");
Py_RETURN_NONE;
}
if (plugin_handle->file_handle) {
file_handle = (void*) PyMolfileCapsule_AsVoidPtr(plugin_handle->file_handle);
} else {
PyErr_Format(PyExc_IOError, "no file handle in molfile plugin handle.");
Py_RETURN_NONE;
}
numatoms = (int) PyArray_DIM((PyArrayObject*)molarray, 1);
if (numatoms<0){
if (plugin_handle->natoms) {
numatoms = plugin_handle->natoms;
if (numatoms<0){
PyErr_Format(PyExc_IOError, "no assigned number of atoms in molfile plugin handle.");
Py_RETURN_NONE;
}
} else {
PyErr_Format(PyExc_AttributeError, "plugin does not have number of atoms information.");
Py_RETURN_NONE;
}
}
// Aquire memory pointer of molfile_atom_t struct from numpy array
data = (molfile_atom_t*) PyArray_DATA((PyArrayObject*)molarray);
// Write array values in molfile_atom_t
if (plugin->write_structure) {
status = plugin->write_structure(file_handle, options, data);
// Check if the status is ok
if (status!=0){
PyErr_Format(PyExc_IOError, "Error in write_structure function of plugin.");
Py_RETURN_FALSE;
}
Py_RETURN_TRUE;
} else {
PyErr_Format(PyExc_AttributeError, "molfile plugin does not have write_structure function.");
Py_RETURN_FALSE;
}
}
PyObject* read_fill_structure(PyObject* molpack, PyObject* prototype)
{
//Py_Initialize();
......@@ -224,14 +280,12 @@ PyObject* read_fill_structure(PyObject* molpack, PyObject* prototype)
MolObject* plugin_handle = (MolObject*) molpack;
if (plugin_handle->plugin) {
plugin = (molfile_plugin_t*) PyMolfileCapsule_AsVoidPtr(plugin_handle->plugin);
//plugin = plugin_handle->plugin;
} else {
PyErr_Format(PyExc_IOError, "molfile plugin is not active.");
return NULL;
}
if (plugin_handle->file_handle) {
file_handle = (void*) PyMolfileCapsule_AsVoidPtr(plugin_handle->file_handle);
//file_handle = plugin_handle->file_handle;
} else {
PyErr_Format(PyExc_IOError, "no file handle in molfile plugin handle.");
return NULL;
......@@ -368,6 +422,81 @@ PyObject* read_fill_bonds(PyObject* molpack)
}
}
PyObject* write_fill_bonds(PyObject* molpack, PyObject* moldict)
{
if(!PyDict_Check(moldict)) {
PyErr_Format(PyExc_IOError, "argument 2 is not a Python dictionary.");
Py_RETURN_FALSE;
}
initNumpyArray();
molfile_plugin_t* plugin;
void* file_handle;
molfile_atom_t* data;
int numatoms, status;
PyObject *ret = NULL;
// Access plugin_handle values
MolObject* plugin_handle = (MolObject*) molpack;
if (plugin_handle->plugin) {
plugin = (molfile_plugin_t*) PyMolfileCapsule_AsVoidPtr(plugin_handle->plugin);
} else {
PyErr_Format(PyExc_IOError, "molfile plugin is not set.");
return NULL;
}
if (plugin_handle->file_handle) {
file_handle = (void*) PyMolfileCapsule_AsVoidPtr(plugin_handle->file_handle);
} else {
PyErr_Format(PyExc_IOError, "no file handle in molfile plugin handle.");
return NULL;
}
numatoms = plugin_handle->natoms;
if (plugin->write_bonds) {
int nbonds, *from, *to, nbondtypes;
int *bondtype = NULL;
float *bondorder = NULL;
char **bondtypename = NULL;
// Lets see whether dictionary includes a numpy array for coords.
PyObject *from_arr = PyDict_GetItemString(moldict, "from");
PyObject *to_arr = PyDict_GetItemString(moldict, "to");
PyObject *bondorder_arr = PyDict_GetItemString(moldict, "bondorder");
PyObject *bondtype_arr = PyDict_GetItemString(moldict, "bondtype");
PyObject *bondtypename_arr = PyDict_GetItemString(moldict, "bondtypename");
if(from_arr && to_arr) {
nbonds = (int) PyArray_DIMS((PyArrayObject*)from_arr)[0];
from = (int*) PyArray_DATA((PyArrayObject*)from_arr);
to = (int*) PyArray_DATA((PyArrayObject*)to_arr);
}
if(bondorder_arr) {
bondorder = (float*) PyArray_DATA((PyArrayObject*)bondorder_arr);
}
nbondtypes = 0;
if(bondtype_arr) {
nbondtypes = (int) PyArray_DIMS((PyArrayObject*)bondtype_arr)[0];
bondtype = (int*) PyArray_DATA((PyArrayObject*)bondtype_arr);
}
if(bondtypename_arr) {
nbondtypes = (int) PyArray_DIMS((PyArrayObject*)bondtypename_arr)[0];
bondtypename = (char**) PyArray_DATA((PyArrayObject*)bondtypename_arr);
}
if (nbonds>0) {
if ((status = plugin->write_bonds(file_handle, nbonds, from, to,
bondorder, bondtype, nbondtypes, bondtypename))) {
PyErr_Format(PyExc_IOError, "Error accessing write_bonds function of plugin.");
Py_RETURN_NONE;
}
if (status!=0){
PyErr_Format(PyExc_IOError, "Error in write_bonds function of plugin.");
Py_RETURN_NONE;
}
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
} else {
PyErr_Format(PyExc_AttributeError, "molfile plugin does not have write_bonds function.");
Py_RETURN_NONE;
}
}
PyObject* read_fill_angles(PyObject* molpack)
{
initNumpyArray();
......@@ -567,6 +696,391 @@ PyObject* read_fill_angles(PyObject* molpack)
}
PyObject* write_fill_angles(PyObject* molpack, PyObject* moldict)
{
if(!PyDict_Check(moldict)) {
PyErr_Format(PyExc_IOError, "argument 2 is not a Python dictionary.");
Py_RETURN_FALSE;
}
initNumpyArray();
int options = 0;
molfile_plugin_t* plugin;
void* file_handle;
molfile_atom_t* data;
int numatoms, status;
// Access plugin_handle values
MolObject* plugin_handle = (MolObject*) molpack;
if (plugin_handle->plugin) {
plugin = (molfile_plugin_t*) PyMolfileCapsule_AsVoidPtr(plugin_handle->plugin);
} else {
PyErr_Format(PyExc_IOError, "molfile plugin is not active.");
return NULL;
}
if (plugin_handle->file_handle) {
file_handle = (void*) PyMolfileCapsule_AsVoidPtr(plugin_handle->file_handle);
} else {
PyErr_Format(PyExc_IOError, "no file handle in molfile plugin handle.");
return NULL;
}
numatoms = plugin_handle->natoms;
// Check if there is write_angles support in this plugin
if (plugin->write_angles) {
// Angles
int numangles;
int *angles = NULL;
int *angletypes = NULL;
int numangletypes;
const char **angletypenames = NULL;
// Dihedrals
int numdihedrals;
int *dihedrals = NULL;
int *dihedraltypes = NULL;
int numdihedraltypes;
const char **dihedraltypenames = NULL;
// Impropers
int numimpropers;
int *impropers = NULL;
int *impropertypes = NULL;
int numimpropertypes;
const char **impropertypenames = NULL;
// Cterms
int ndimcterms = 2;
int numcterms, ctermcols, ctermrows;
int *cterms = NULL;
// Initilize zeros to number of angles, dihedrals, so on ...
numangles = 0;
numangletypes = 0;
numdihedrals = 0;
numdihedraltypes = 0;
numimpropers = 0;
numimpropertypes = 0;
numcterms = 0;
// Lets see whether dictionary includes a numpy arrays.
PyObject *angles_arr = PyDict_GetItemString(moldict, "angles");
PyObject *angletypes_arr = PyDict_GetItemString(moldict, "angletypes");
PyObject *angletypenames_arr = PyDict_GetItemString(moldict, "angletypenames");
PyObject *dihedrals_arr = PyDict_GetItemString(moldict, "dihedrals");
PyObject *dihedraltypes_arr = PyDict_GetItemString(moldict, "dihedraltypes");
PyObject *dihedraltypenames_arr = PyDict_GetItemString(moldict, "dihedraltypenames");
PyObject *impropers_arr = PyDict_GetItemString(moldict, "impropers");
PyObject *impropertypes_arr = PyDict_GetItemString(moldict, "impropertypes");
PyObject *impropertypenames_arr = PyDict_GetItemString(moldict, "impropertypenames");
PyObject *cterms_arr = PyDict_GetItemString(moldict, "cterms");
// Even if there is no info for angles/dihedrals/impropers, this function will let the
// the arrays to be NULL on plugin level.
// We will do the checking one-by-one for all available numpy arrays
if(angles_arr) {
numangles = (int) PyArray_DIMS((PyArrayObject*)angles_arr)[0];
angles = (int*) PyArray_DATA((PyArrayObject*)angles_arr);
}
if(angletypes_arr) {
numangletypes = (int) PyArray_DIMS((PyArrayObject*)angletypes_arr)[0];
angletypes = (int*) PyArray_DATA((PyArrayObject*)angletypes_arr);
}
if(angletypenames_arr) {
numangletypes = (int) PyArray_DIMS((PyArrayObject*)angletypenames_arr)[0];
angletypenames = (const char**) PyArray_DATA((PyArrayObject*)angletypenames_arr);
}
if(dihedrals_arr) {
numdihedrals = (int) PyArray_DIMS((PyArrayObject*)dihedrals_arr)[0];
dihedrals = (int*) PyArray_DATA((PyArrayObject*)dihedrals_arr);
}
if(dihedraltypes_arr) {
numdihedraltypes = (int) PyArray_DIMS((PyArrayObject*)dihedraltypes_arr)[0];
dihedraltypes = (int*) PyArray_DATA((PyArrayObject*)dihedraltypes_arr);
}
if(dihedraltypenames_arr) {
numdihedraltypes = (int) PyArray_DIMS((PyArrayObject*)dihedraltypenames_arr)[0];
dihedraltypenames = (const char**) PyArray_DATA((PyArrayObject*)dihedraltypenames_arr);
}
if(impropers_arr) {
numimpropers = (int) PyArray_DIMS((PyArrayObject*)impropers_arr)[0];
impropers = (int*) PyArray_DATA((PyArrayObject*)impropers_arr);
}
if(impropertypes_arr) {
numimpropertypes = (int) PyArray_DIMS((PyArrayObject*)impropertypes_arr)[0];
impropertypes = (int*) PyArray_DATA((PyArrayObject*)impropertypes_arr);
}
if(impropertypenames_arr) {
numimpropertypes = (int) PyArray_DIMS((PyArrayObject*)impropertypenames_arr)[0];
impropertypenames = (const char**) PyArray_DATA((PyArrayObject*)impropertypenames_arr);
}
// Cterms
if(cterms_arr) {
ndimcterms = (int) PyArray_NDIM((PyArrayObject*)cterms_arr);
numcterms = (int) PyArray_SIZE((PyArrayObject*)cterms_arr);
if (ndimcterms>1) {
ctermrows = (int) PyArray_DIMS((PyArrayObject*)cterms_arr)[0];
ctermcols = (int) PyArray_DIMS((PyArrayObject*)cterms_arr)[1];
} else {
ctermrows = 0;
ctermcols = 0;
}
cterms = (int*) PyArray_DATA((PyArrayObject*)cterms_arr);
}
// Calling write_angles to write the information
if ((status = plugin->write_angles(file_handle, numangles, angles, angletypes,
numangletypes, angletypenames, numdihedrals,
dihedrals, dihedraltypes, numdihedraltypes,
dihedraltypenames, numimpropers, impropers,
impropertypes, numimpropertypes, impropertypenames,
numcterms, cterms, ctermcols, ctermrows))) {
PyErr_Format(PyExc_IOError, "Error accessing read_angles function of plugin.");
Py_RETURN_NONE;
}
Py_RETURN_TRUE;
} else {
PyErr_Format(PyExc_AttributeError, "molfile plugin does not have read_angles function.");
Py_RETURN_NONE;
}
}
PyObject* write_fill_timestep(PyObject* molpack, PyObject* moldict)
{
if(!PyDict_Check(moldict)) {
PyErr_Format(PyExc_IOError, "argument 2 is not a Python dictionary.");
Py_RETURN_FALSE;
}
initNumpyArray();
molfile_plugin_t* plugin;
void* file_handle;
int numatoms, status;
int nd;
int i, d;
// Access plugin_handle values
MolObject* plugin_handle = (MolObject*) molpack;
if (plugin_handle->plugin) {
plugin = (molfile_plugin_t*) PyMolfileCapsule_AsVoidPtr(plugin_handle->plugin);
} else {
PyErr_Format(PyExc_IOError, "molfile plugin is not active.");
Py_RETURN_NONE;
}
if (plugin_handle->file_handle) {
file_handle = (void*) PyMolfileCapsule_AsVoidPtr(plugin_handle->file_handle);
} else {
PyErr_Format(PyExc_IOError, "no file handle in molfile plugin handle.");
Py_RETURN_NONE;
}
if (plugin_handle->natoms) {
numatoms = plugin_handle->natoms;
} else {
PyErr_Format(PyExc_IOError, "no assigned number of atoms in molfile plugin handle.");
Py_RETURN_NONE;
}
if (plugin->write_timestep) {
PyObject *coords_arr = NULL;
npy_intp n, m, i, j;
int ndim = 1;
// Lets see whether dictionary includes a numoy array for coords.
// We will use the first dimension as the loop over write_timestep.
coords_arr = PyDict_GetItemString(moldict, "coords");
if(coords_arr) {
ndim = (int) PyArray_NDIM((PyArrayObject*)coords_arr);
} else {
// It seams someone forgot to put coords in dictionary.
// Nothing to write to output file
// Return False in this case
Py_RETURN_FALSE;
}
int numsteps = 0;
int numatoms = 0;
// Check if dimension is correct for numpy array
// If the array dimension is not correct return False.
if(ndim>2){
n = PyArray_DIMS((PyArrayObject*)coords_arr)[0];
m = PyArray_DIMS((PyArrayObject*)coords_arr)[1];
numsteps = (int)n;
numatoms = (int)m;
}
else if(ndim>1){
n = 1;
m = PyArray_DIMS((PyArrayObject*)coords_arr)[0];
numsteps = (int)n;
numatoms = (int)m;
} else {
Py_RETURN_FALSE;
}
//if(numsteps>0){
// molfile_timestep_t timestep;
//} else {
// Py_RETURN_FALSE;
//}
// It seams we have coordinates in a numpy array and
// if we have at least one snapshot of coordinates, we can write it.
// Set if the velocities can be written with this plugin
int has_velocities = 0;
unsigned int total_steps = 1;
unsigned int bytes_per_step = 0;
double a_sca, b_sca, c_sca, alpha_sca, beta_sca, gamma_sca, time_sca;
//molfile_timestep_metadata_t timestep_metadata;
PyObject *bytes_per_step_arr = PyDict_GetItemString(moldict, "bytes_per_step");
if(bytes_per_step_arr) {
bytes_per_step = (unsigned int)PyLong_AsLong(bytes_per_step_arr);
//timestep_metadata.avg_bytes_per_timestep = bytes_per_step;
}
PyObject *total_steps_arr = PyDict_GetItemString(moldict, "total_steps");
if(total_steps_arr){
total_steps = (unsigned int)PyLong_AsLong(total_steps_arr);
//timestep_metadata.count = total_steps;
}
PyObject *has_velocities_arr = PyDict_GetItemString(moldict, "has_velocities");
if(has_velocities_arr){
has_velocities = (int)PyLong_AsLong(has_velocities_arr);
//timestep_metadata.has_velocities = has_velocities;
}
PyObject *velocities_arr = NULL;
if(has_velocities > 0) {
velocities_arr = PyDict_GetItemString(moldict, "velocities");
}
// All support arrays' sizes should match the size of coords array if supplied.
PyObject *a_arr = PyDict_GetItemString(moldict, "A");
if(a_arr)
if(PyArray_Check(a_arr)){
if(n != PyArray_DIMS((PyArrayObject*)a_arr)[0])
Py_RETURN_FALSE;
} else {
a_sca = PyFloat_AsDouble(a_arr);
}
PyObject *b_arr = PyDict_GetItemString(moldict, "B");
if(b_arr)
if(PyArray_Check(b_arr)){
if(n != PyArray_DIMS((PyArrayObject*)b_arr)[0])
Py_RETURN_FALSE;
} else {
b_sca = PyFloat_AsDouble(b_arr);
}
PyObject *c_arr = PyDict_GetItemString(moldict, "C");
if(c_arr)
if(PyArray_Check(c_arr)){
if(n != PyArray_DIMS((PyArrayObject*)c_arr)[0])
Py_RETURN_FALSE;
} else {
c_sca = PyFloat_AsDouble(c_arr);
}
PyObject *alpha_arr = PyDict_GetItemString(moldict, "alpha");
if(alpha_arr)
if(PyArray_Check(alpha_arr)){
if(n != PyArray_DIMS((PyArrayObject*)alpha_arr)[0])
Py_RETURN_FALSE;
} else {
alpha_sca = PyFloat_AsDouble(alpha_arr);
}
PyObject *beta_arr = PyDict_GetItemString(moldict, "beta");
if(beta_arr)
if(PyArray_Check(beta_arr)){
if(n != PyArray_DIMS((PyArrayObject*)beta_arr)[0])
Py_RETURN_FALSE;
} else {
beta_sca = PyFloat_AsDouble(beta_arr);
}
PyObject *gamma_arr = PyDict_GetItemString(moldict, "gamma");
if(gamma_arr)
if(PyArray_Check(gamma_arr)){
if(n != PyArray_DIMS((PyArrayObject*)gamma_arr)[0])
Py_RETURN_FALSE;
} else {
gamma_sca = PyFloat_AsDouble(gamma_arr);
}
PyObject *pt_arr = PyDict_GetItemString(moldict, "physical_time");
if(pt_arr)
if(PyArray_Check(pt_arr)){
if(n != PyArray_DIMS((PyArrayObject*)pt_arr)[0])
Py_RETURN_FALSE;