Commit f31ef5f0 authored by Michael Banck's avatar Michael Banck

New upstream version 1.6

parent ca9be2f7
# The full list of properties is located at
# https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties.
root = true
[*.py]
charset = utf-8
indent_style = space
indent_size = 4
[.travis.yml]
indent_style = space
indent_size = 2
......@@ -3,7 +3,7 @@ dist: trusty
language: python
python:
- 2.7
- 3.2
- 3.4
- 3.6
addons:
apt:
......@@ -12,9 +12,31 @@ addons:
- swig
cache:
pip: true
before_install:
- pip install -r requirements.txt
install:
- python setup.py install
- pip install .
before_script:
- |
export DOCS_BRANCH_NAME=master
export DOCS_REPO_NAME=cclib.github.io
export DOCS_REPO_OWNER=cclib
export DOCS_ROOT_DIR="${TRAVIS_BUILD_DIR}"/doc/sphinx
export DOCS_BUILD_DIR="${DOCS_ROOT_DIR}"/_build/html
export THEME_DIR="${DOCS_ROOT_DIR}"/_themes
- install -dm755 "${THEME_DIR}"
script:
- sh travis/run_travis_tests.sh
- bash travis/run_travis_tests.sh
- bash travis/build_docs.bash
- env | sort
- |
if [[ "${TRAVIS_BRANCH}" == master && "${TRAVIS_PULL_REQUEST}" == false && $TRAVIS_PYTHON_VERSION == 3.6 ]];
then
# Commits to master that are not pull requests, that is, only actual
# addition of code to master, should deploy the documentation.
bash ${TRAVIS_BUILD_DIR}/travis/deploy_docs_travis.bash
fi
On behalf of the cclib development team, we are pleased to announce the release of cclib 1.5.3, which is now available for download from https://cclib.github.io. This is a minor update to version 1.5 that includes some new functionality and attributes, as well as bug fixes and small improvements.
On behalf of the cclib development team, we are pleased to announce the release of cclib 1.6, which is now available for download from https://cclib.github.io. This is a new minor version that includes two new parsers, some new functionality and attributes, as well as bug fixes and small improvements.
cclib is an open source library, written in Python, for parsing and interpreting the results of computational chemistry packages. It currently parses output files from 13 different programs: ADF, DALTON, Firefly, GAMESS (US), GAMESS-UK, Gaussian, Jaguar, Molpro, MOPAC, NWChem, ORCA, Psi and QChem.
cclib is an open source library, written in Python, for parsing and interpreting the results of computational chemistry packages. It currently parses output files from 15 different programs: ADF, DALTON, Firefly, GAMESS (US), GAMESS-UK, Gaussian, Jaguar, Molpro, MOLCAS, MOPAC, NWChem, ORCA, Psi, QChem and Turbomole.
Among other data, cclib extracts:
......@@ -28,7 +28,7 @@ If you need help, find a bug, want new features or have any questions, please se
If your published work uses cclib, please support its development by citing the following article:
N. M. O'Boyle, A. L. Tenderholt, K. M. Langner, cclib: a library for package-independent computational chemistry algorithms, J. Comp. Chem. 29 (5), 839-845 (2008)
You can also specifically reference this version of cclib as:
Eric Berquist, Karol M. Langner, Noel M. O'Boyle, and Adam L. Tenderholt. Release of cclib version 1.5. 2016. https://dx.doi.org/10.5281/zenodo.60670
Eric Berquist, Karol M. Langner, Noel M. O'Boyle, and Adam L. Tenderholt. Release of cclib version 1.6. 2018. https://dx.doi.org/10.5281/zenodo.1407790
Regards,
The cclib development team
......
Changes in cclib-1.6
Features:
* New parser: cclib can now parse Molcas files (Kunal Sharma)
* New parser: cclib can now parse Turbomole files (Christopher Rowley, Kunal Sharma)
* New script: ccframe writes data table files from logfiles (Felipe Schneider)
* New method: stoichiometry builds the chemical formula of a system (Jaime Rodríguez-Guerra)
* Support package version in metadata for most parsers
* Support time attribute and BOMD output in Gaussian, NWChem, ORCA and QChem
* Support grads and metadata attributes in ORCA (Jonathon Vandezande)
* Experimental support for CASSCF output in ORCA (Jonathon Vandezande)
* Added entry in metadata for successful completion of jobs
* Updated test file versions to ORCA 4.0
* Update minimum Python3 version to 3.4
Bugfixes:
* Fixed parsing ORCA output with linear molecules (Jonathon Vandezande)
* Fixed parsing NWChem output with incomplete SCF
Changes in cclib-1.5.3
Features:
......@@ -13,20 +32,20 @@ Bugfixes:
* Fixed closed shell determination for Gaussian (Jaime Rodríguez-Guerra)
* Fixed parsing of natom for >9999 atoms in Gaussian (Jaime Rodríguez-Guerra)
* Fixed parsing of ADF jobs with no title
* Fixed parsing of charge and core electrons when usin ECPs in QChem
* Fixed parsing of charge and core electrons when using ECPs in QChem
* Fixed parsing of scfvalues for malformed output in Gaussian
Changes in cclib-1.5.2:
Features:
* Support for writing Molden and WFX files (Sagar Gaur)
* Support for thermochesmitry attributes in ORCA (Jonathon Vandezande)
* Support for thermochemistry attributes in ORCA (Jonathon Vandezande)
* Support for chelpg atomic charges in ORCA (Richard Gowers)
* Updated test file versions to GAMESS-US 2017 (Sagar Gaur)
* Added option to print full arrays with ccget (Sagar Gaur)
Bugfixes:
* Fxied polarizability parsing bug in DALTON (Maxim Stolyarchuk)
* Fixed polarizability parsing bug in DALTON (Maxim Stolyarchuk)
* Fixed IRC parsing in Gaussian for large trajectories (Dénes Berta, LaTruelle)
* Fixed coordinate parsing for heavy elements in ORCA (Jonathon Vandezande)
* Fixed parsing of large mocoeffs in fixed width format for QChem (srtlg)
......@@ -46,7 +65,7 @@ Bugfixes:
* Restore alias cclib.parser.ccopen for backwards compatibility
* Fixed parsing thermochemistry for single atoms in QChem
* Fixed handling of URLs (Alexey Alnatanov)
* Fixed Atom object creation in biopython bridge (Nitish Garg)
* Fixed Atom object creation in Biopython bridge (Nitish Garg)
* Fixed ccopen when working with multiple files
Changes in cclib-1.5:
......@@ -57,7 +76,7 @@ Features:
* New attribute time tracks coordinates for dynamics jobs (Ramon Crehuet)
* New attribute metadata holds miscellaneous information not in other attributes (bwang2453)
* Extract moments attribute for Gaussian (Geoff Hutchison)
* Extract atombasis for ADF in simple cases (Felix Plaser)
* Extract atombasis for ADF in simple cases (Felix Plasser)
* License change to BSD 3-Clause License
Bugfixes:
......@@ -75,7 +94,7 @@ Features:
Bugfixes:
* Fix for non-standard basis sets in DALTON
* Fix for non-standard MO coefficient printin in GAMESS
* Fix for non-standard MO coefficient printing in GAMESS
Changes in cclib-1.4:
......@@ -97,10 +116,10 @@ Bugfixes:
* Fix parsing basis section for Molpro job generated by Avogadro
* Fix parsing multi-job Gaussian output with different orbitals (Geoff Hutchinson)
* Fix parsing ORCA geometry optimization with improper internal coordinates (glideht)
* Fix units in atom corodinates parsed from GAMESS-UK files (mwykes)
* Fix units in atom coordinates parsed from GAMESS-UK files (mwykes)
* Fix test for vibrational frequencies in Turbomole (mwykes)
* Fix parsing vibration symmetries for Molpro (mwykes)
* Fix parsing egenvectors in GAMESS-US (Alexis Otero-Calvis)
* Fix parsing eigenvectors in GAMESS-US (Alexis Otero-Calvis)
* Fix duplicate parsing of symmetry labels for Gaussian (Martin Peeks)
Changes in cclib-1.3.1:
......@@ -140,7 +159,7 @@ Bugfixes:
Changes in cclib-1.2:
Features:
* Move project to github
* Move project to GitHub
* Transition to Python 3 (Python 2.7 will still work)
* Add a multifile mode to ccget script
* Extract vibrational displacements for ORCA
......@@ -150,8 +169,8 @@ Features:
Gaussian09, Molpro 2012 and ORCA 3.0.1
Bugfixes:
* Ignore unicode errors in logfiles
* Handle Guassian jobs with terse output (basis set count not reported)
* Ignore Unicode errors in logfiles
* Handle Gaussian jobs with terse output (basis set count not reported)
* Handle Gaussian jobs using IndoGuess (Scott McKechnie)
* Handle Gaussian file with irregular ONION gradients (Tamilmani S)
* Handle ORCA file with SCF convergence issue (Melchor Sanchez)
......@@ -164,9 +183,9 @@ Changes in cclib-1.1:
Features:
* Add progress info for all parsers
* Support ONIOM calculations in Gaussian (Karen Hemelsoet)
* New attribute atomcharges extracts Mulliken and Lowdin atomic
* New attribute atomcharges extracts Mulliken and Löwdin atomic
charges if present
* New attribute atomspins extracts Mulliken and Lowdin atomic spin
* New attribute atomspins extracts Mulliken and Löwdin atomic spin
densities if present
* New thermodynamic attributes: freeenergy, temperature, enthalpy
(Edward Holland)
......@@ -252,7 +271,7 @@ Features:
* GAMESS-US parser: added 'etoscs' (CIS calculations)
* Jaguar parser: added 'mpenergies' (LMP2 calcualtions)
* Jaguar parser: added 'etenergies' and 'etoscs' (CIS calculations)
* New method: Lowdin Population Analysis (LPA)
* New method: Löwdin Population Analysis (LPA)
* Tests: unittests can be run from the Python interpreter, and for
a single parser; the number of "passed" tests is also counted and shown
......@@ -270,7 +289,7 @@ Features:
* API addition: 'gbasis' holds the Gaussian basis set
* API addition: 'coreelectrons' contains the number of core electrons
in each atom's pseudopotential
* API addition: 'mpenergies' holds the Moller-Plesset corrected
* API addition: 'mpenergies' holds the Møller-Plesset corrected
molecular electronic energies
* API addition: 'vibdisps' holds the Cartesian displacement vectors
* API change: 'mocoeffs' is now a list of rank 2 arrays, rather than a
......
......@@ -55,7 +55,7 @@ To test, trying importing cclib at the Python prompt. You should see something s
History is saved to ~/.pyhistory.
>>> import cclib
>>> cclib.__version__
'1.5.3'
'1.6'
To run the unit tests, change directory into INSTALLDIR/test and run the following command:
......
### cclib
[![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.50324.svg)](https://dx.doi.org/10.5281/zenodo.60670)
[![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.1407790.svg)](https://dx.doi.org/10.5281/zenodo.1407790)
[![PyPI version](http://img.shields.io/pypi/v/cclib.svg?style=flat)](https://pypi.python.org/pypi/cclib)
[![GitHub release](https://img.shields.io/github/release/cclib/cclib.svg?style=flat)](https://github.com/cclib/cclib/releases)
[![build status](http://img.shields.io/travis/cclib/cclib/master.svg?style=flat)](https://travis-ci.org/cclib/cclib)
......
......@@ -23,7 +23,7 @@ To this end, cclib provides a number of bridges to help transfer data to other l
as well as example methods that take parsed data as input.
"""
__version__ = "1.5.3"
__version__ = "1.6"
from cclib import parser
from cclib import progress
......
......@@ -5,20 +5,23 @@
# This file is part of cclib (http://cclib.github.io) and is distributed under
# the terms of the BSD 3-Clause License.
"""Contains all writers for standard chemical representations"""
"""Contains all writers for standard chemical representations."""
from cclib.io.cjsonreader import CJSON as CJSONReader
from cclib.io.cjsonwriter import CJSON as CJSONWriter
from cclib.io.cmlwriter import CML
from cclib.io.xyzwriter import XYZ
from cclib.io.moldenwriter import MOLDEN
from cclib.io.wfxwriter import WFXWriter
from cclib.io.cjsonreader import CJSON as CJSONReader
from cclib.io.xyzreader import XYZ as XYZReader
from cclib.io.xyzwriter import XYZ as XYZWriter
# This allows users to type:
# from cclib.io import ccframe
# from cclib.io import ccopen
# from cclib.io import ccread
# from cclib.io import ccwrite
# from cclib.io import URL_PATTERN
from cclib.io.ccio import ccframe
from cclib.io.ccio import ccopen
from cclib.io.ccio import ccread
from cclib.io.ccio import ccwrite
......
......@@ -10,12 +10,12 @@
from __future__ import print_function
import atexit
import io
import os
import sys
import re
from tempfile import NamedTemporaryFile
import atexit
# Python 2->3 changes the default file object hierarchy.
if sys.version_info[0] == 2:
......@@ -23,12 +23,12 @@ if sys.version_info[0] == 2:
from urllib2 import urlopen, URLError
else:
import io
fileclass = io.IOBase
from urllib.request import urlopen
from urllib.error import URLError
from cclib.parser import logfileparser
from cclib.parser import data
......@@ -38,19 +38,23 @@ from cclib.parser.gamessparser import GAMESS
from cclib.parser.gamessukparser import GAMESSUK
from cclib.parser.gaussianparser import Gaussian
from cclib.parser.jaguarparser import Jaguar
from cclib.parser.molcasparser import Molcas
from cclib.parser.molproparser import Molpro
from cclib.parser.mopacparser import MOPAC
from cclib.parser.nwchemparser import NWChem
from cclib.parser.orcaparser import ORCA
from cclib.parser.psiparser import Psi
from cclib.parser.psi3parser import Psi3
from cclib.parser.psi4parser import Psi4
from cclib.parser.qchemparser import QChem
from cclib.parser.turbomoleparser import Turbomole
from cclib.io import cjsonreader
from cclib.io import cjsonwriter
from cclib.io import cmlwriter
from cclib.io import xyzwriter
from cclib.io import moldenwriter
from cclib.io import wfxwriter
from cclib.io import xyzreader
from cclib.io import xyzwriter
try:
from cclib.bridge import cclib2openbabel
......@@ -58,6 +62,11 @@ try:
except ImportError:
_has_cclib2openbabel = False
try:
import pandas as pd
except ImportError:
# Fail silently for now.
pass
# Regular expression for validating URLs
URL_PATTERN = re.compile(
......@@ -78,8 +87,7 @@ URL_PATTERN = re.compile(
# after finding GAMESS in case the more specific phrase is found.
# 2. Molpro log files don't have the program header, but always contain
# the generic string 1PROGRAM, so don't break here either to be cautious.
# 3. The Psi header has two different strings with some variation
# 4. "MOPAC" is used in some packages like GAMESS, so match MOPAC20##
# 3. "MOPAC" is used in some packages like GAMESS, so match MOPAC20##
#
# The triggers are defined by the tuples in the list below like so:
# (parser, phrases, flag whether we should break)
......@@ -92,23 +100,32 @@ triggers = [
(GAMESSUK, ["G A M E S S - U K"], True),
(Gaussian, ["Gaussian, Inc."], True),
(Jaguar, ["Jaguar"], True),
(Molcas, ["MOLCAS"], True),
(Molpro, ["PROGRAM SYSTEM MOLPRO"], True),
(Molpro, ["1PROGRAM"], False),
(MOPAC, ["MOPAC20"], True),
(NWChem, ["Northwest Computational Chemistry Package"], True),
(ORCA, ["O R C A"], True),
(Psi, ["PSI", "Ab Initio Electronic Structure"], True),
(Psi3, ["PSI3: An Open-Source Ab Initio Electronic Structure Package"], True),
(Psi4, ["Psi4: An Open-Source Ab Initio Electronic Structure Package"], True),
(QChem, ["A Quantum Leap Into The Future Of Chemistry"], True),
(Turbomole, ["TURBOMOLE"], True),
]
outputclasses = {
readerclasses = {
'cjson': cjsonreader.CJSON,
'json': cjsonreader.CJSON,
'xyz': xyzreader.XYZ,
}
writerclasses = {
'cjson': cjsonwriter.CJSON,
'json': cjsonwriter.CJSON,
'cml': cmlwriter.CML,
'xyz': xyzwriter.XYZ,
'molden': moldenwriter.MOLDEN,
'wfx': wfxwriter.WFXWriter
'wfx': wfxwriter.WFXWriter,
'xyz': xyzwriter.XYZ,
}
......@@ -171,9 +188,9 @@ def ccopen(source, *args, **kargs):
*args, **kargs - arguments and keyword arguments passed to filetype
Returns:
one of ADF, DALTON, GAMESS, GAMESS UK, Gaussian, Jaguar, Molpro, MOPAC,
NWChem, ORCA, Psi, QChem, CJSON or None (if it cannot figure it out or
the file does not exist).
one of ADF, DALTON, GAMESS, GAMESS UK, Gaussian, Jaguar,
Molpro, MOPAC, NWChem, ORCA, Psi3, Psi/Psi4, QChem, CJSON or None
(if it cannot figure it out or the file does not exist).
"""
inputfile = None
......@@ -255,12 +272,17 @@ def ccopen(source, *args, **kargs):
# Proceed to return an instance of the logfile parser only if the filetype
# could be guessed. Need to make sure the input file is closed before creating
# an instance, because parsers will handle opening/closing on their own.
# If the input file is a CJSON file and not a standard compchemlog file, don't
# guess the file.
if kargs.get("cjson", False):
filetype = cjsonreader.CJSON
else:
filetype = guess_filetype(inputfile)
filetype = guess_filetype(inputfile)
# If the input file isn't a standard compchem log file, try one of
# the readers, falling back to Open Babel.
if not filetype:
if kargs.get("cjson"):
filetype = readerclasses['cjson']
elif source and not is_stream:
ext = os.path.splitext(source)[1][1:].lower()
for extension in readerclasses:
if ext == extension:
filetype = readerclasses[extension]
# Proceed to return an instance of the logfile parser only if the filetype
# could be guessed. Need to make sure the input file is closed before creating
......@@ -275,6 +297,9 @@ def ccopen(source, *args, **kargs):
else:
inputfile.seek(0, 0)
if not is_stream:
if is_listofstrings:
if filetype == Turbomole:
source = sort_turbomole_outputs(source)
inputfile.close()
return filetype(source, *args, **kargs)
return filetype(inputfile, *args, **kargs)
......@@ -381,8 +406,8 @@ def _determine_output_format(outputtype, outputdest):
# First check outputtype.
if isinstance(outputtype, str):
extension = outputtype.lower()
if extension in outputclasses:
outputclass = outputclasses[extension]
if extension in writerclasses:
outputclass = writerclasses[extension]
else:
raise UnknownOutputFormatError(extension)
else:
......@@ -393,9 +418,92 @@ def _determine_output_format(outputtype, outputdest):
extension = os.path.splitext(outputdest.name)[1].lower()
else:
raise UnknownOutputFormatError
if extension in outputclasses:
outputclass = outputclasses[extension]
if extension in writerclasses:
outputclass = writerclasses[extension]
else:
raise UnknownOutputFormatError(extension)
return outputclass
def path_leaf(path):
"""
Splits the path to give the filename. Works irrespective of '\'
or '/' appearing in the path and also with path ending with '/' or '\'.
Inputs:
path - a string path of a logfile.
Returns:
tail - 'directory/subdirectory/logfilename' will return 'logfilename'.
ntpath.basename(head) - 'directory/subdirectory/logfilename/' will return 'logfilename'.
"""
head, tail = os.path.split(path)
return tail or os.path.basename(head)
def sort_turbomole_outputs(filelist):
"""
Sorts a list of inputs (or list of log files) according to the order
defined below. Just appends the unknown files in the end of the sorted list.
Inputs:
filelist - a list of Turbomole log files needed to be parsed.
Returns:
sorted_list - a sorted list of Turbomole files needed for proper parsing.
"""
sorting_order = {
'basis' : 0,
'control' : 1,
'mos' : 2,
'alpha' : 3,
'beta' : 4,
'job.last' : 5,
'coord' : 6,
'gradient' : 7,
'aoforce' : 8,
}
known_files = []
unknown_files = []
sorted_list = []
for fname in filelist:
filename = path_leaf(fname)
if filename in sorting_order:
known_files.append([fname, sorting_order[filename]])
else:
unknown_files.append(fname)
for i in sorted(known_files, key=lambda x: x[1]):
sorted_list.append(i[0])
if unknown_files:
sorted_list.append(known_files)
return sorted_list
def ccframe(ccobjs, *args, **kwargs):
"""Returns a pandas.DataFrame of data attributes parsed by cclib from one
or more logfiles.
Inputs:
ccobjs - an iterable of either cclib jobs (from ccopen) or data (from
job.parse()) objects
Returns:
a pandas.DataFrame
"""
logfiles = []
for ccobj in ccobjs:
# Is ccobj an job object (unparsed), or is it a ccdata object (parsed)?
if isinstance(ccobj, logfileparser.Logfile):
jobfilename = ccobj.filename
ccdata = ccobj.parse()
elif isinstance(ccobj, data.ccData):
jobfilename = None
ccdata = ccobj
else:
raise ValueError
attributes = ccdata.getattributes()
attributes.update({
'jobfilename': jobfilename
})
logfiles.append(pd.Series(attributes))
return pd.DataFrame(logfiles)
......@@ -27,7 +27,8 @@ class CJSON:
def read_cjson(self):
inputfile = self.filename
json_data = json.loads(open(inputfile).read())
with open(inputfile) as cjsonfile:
json_data = json.loads(cjsonfile.read())
# Actual update of attribute dictionary happens here
self.construct(json_data)
......
......@@ -38,9 +38,8 @@ class CJSON(filewriter.Writer):
name = os.path.basename(os.path.splitext(path)[0])
return name
def generate_repr(self):
"""Generate the CJSON representation of the logfile data."""
def as_dict(self):
""" Build a Python dict with the CJSON data"""
cjson_dict = dict()
# Need to decide on a number format.
cjson_dict['chemical json'] = 0
......@@ -138,7 +137,11 @@ class CJSON(filewriter.Writer):
if _has_openbabel:
cjson_dict['properties']['molecular mass'] = self.pbmol.molwt
cjson_dict['diagram'] = self.pbmol.write(format='svg')
return cjson_dict
def generate_repr(self):
"""Generate the CJSON representation of the logfile data."""
cjson_dict = self.as_dict()
if self.terse:
return json.dumps(cjson_dict, cls=NumpyAwareJSONEncoder)
else:
......@@ -150,13 +153,14 @@ class CJSON(filewriter.Writer):
object: Python dictionary which is being appended with the key value.
key: cclib attribute name.
Returns:
Returns:
None. The dictionary is modified to contain the attribute with the
cclib keyname as key
"""
if hasattr(self.ccdata, key):
object[ccData._attributes[key].jsonKey] = getattr(self.ccdata, key)
class NumpyAwareJSONEncoder(json.JSONEncoder):
"""A encoder for numpy.ndarray's obtained from the cclib attributes.
For all other types the json default encoder is called.
......
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017, the cclib development team
#
# This file is part of cclib (http://cclib.github.io) and is distributed under
# the terms of the BSD 3-Clause License.
"""Generic file reader and related tools"""
class Reader(object):
"""Abstract class for reader objects."""
def __init__(self, source, *args, **kwargs):
"""Initialize the Reader object.
This should be called by a subclass in its own __init__ method.
Inputs:
source - A single filename, stream [TODO], or list of filenames/streams [TODO].
"""
if isinstance(source, str):
self.filename = source
else:
raise ValueError
def parse(self):
"""Read the raw contents of the source into the Reader."""
# TODO This cannot currently handle streams.
with open(self.filename) as handle:
self.filecontents = handle.read()
return None
def generate_repr(self):
"""Convert the raw contents of the source into the internal representation.
This should be overriden by all the subclasses inheriting from
Reader.
"""
raise NotImplementedError(
'generate_repr is not implemented for ' + str(type(self)))
......@@ -7,6 +7,11 @@
"""Generic file writer and related tools"""
import logging
from math import sqrt
from collections import Iterable
try:
from cclib.bridge import makeopenbabel
import openbabel as ob
......@@ -15,9 +20,6 @@ try:
except ImportError:
_has_openbabel = False
from math import sqrt
from collections import Iterable
from cclib.parser.utils import PeriodicTable
......@@ -86,10 +88,20 @@ class Writer(object):
def _make_openbabel_from_ccdata(self):
"""Create Open Babel and Pybel molecules from ccData.
"""
if not hasattr(self.ccdata, 'charge'):
logging.warning("ccdata object does not have charge, setting to 0")
_charge = 0
else:
_charge = self.ccdata.charge
if not hasattr(self.ccdata, 'mult'):
logging.warning("ccdata object does not have spin multiplicity, setting to 1")
_mult = 1
else:
_mult = self.ccdata.mult
obmol = makeopenbabel(self.ccdata.atomcoords,
self.ccdata.atomnos,
charge=self.ccdata.charge,
mult=self.ccdata.mult)
charge=_charge,
mult=_mult)
if self.jobfilename is not None:
obmol.SetTitle(self.jobfilename)
return (obmol, pb.Molecule(obmol))
......
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017, the cclib development team
#
# This file is part of cclib (http://cclib.github.io) and is distributed under
# the terms of the BSD 3-Clause License.
"""A reader for XYZ (Cartesian coordinate) files."""
from cclib.io import filereader
from cclib.parser.data import ccData
from cclib.parser.utils import PeriodicTable
class XYZ(filereader.Reader):
"""A reader for XYZ (Cartesian coordinate) files."""
def __init__(self, source, *args, **kwargs):
super(XYZ, self).__init__(source, *args, **kwargs)
self.pt = PeriodicTable()
def parse(self):
super(XYZ, self).parse()
self.generate_repr()
return self.data
def generate_repr(self):
"""Convert the raw contents of the source into the internal representation."""
assert hasattr(self, 'filecontents')
it = iter(self.filecontents.splitlines())
# Ordering of lines:
# 1. number of atoms
# 2. comment line
# 3. line of at least 4 columns: 1 is atomic symbol (str), 2-4 are atomic coordinates (float)
# repeat for numver of atoms
# (4. optional blank line)