Commit 069ac240 authored by Lauri Himanen's avatar Lauri Himanen
Browse files

Cleaner base class for parsers.

parent 4e44b0a4
......@@ -2,5 +2,4 @@
import cp2kparser.generics.logconfig
from pint import UnitRegistry
import os
ureg = UnitRegistry()
ureg.load_definitions(os.path.dirname(__file__)+"/unit_registry.txt")
ureg = UnitRegistry(os.path.dirname(__file__)+"/unit_registry.txt")
# Pint constants for NomadParsers
# source: http://physics.nist.gov/cuu/Constants/Table/allascii.txt
# Source: http://physics.nist.gov/cuu/Constants/Table/allascii.txt
# Bohr radius
speed_of_light = 299792458 * meter / second = c
standard_gravity = 9.806650 * meter / second ** 2 = g_0 = g_n = gravity
vacuum_permeability = 4 * pi * 1e-7 * newton / ampere ** 2 = mu_0 = magnetic_constant
vacuum_permittivity = 1 / (mu_0 * c **2 ) = epsilon_0 = electric_constant
Z_0 = mu_0 * c = impedance_of_free_space = characteristic_impedance_of_vacuum
bohr = 0.52917721067e-10 m
# 0.000 000 29 e-34
planck_constant = 6.62606957e-34 J s = h
hbar = planck_constant / (2 * pi) = ħ
# 0.000 80 e-11
newtonian_constant_of_gravitation = 6.67384e-11 m^3 kg^-1 s^-2
# 0.000 000 035 e-19
# elementary_charge = 1.602176565e-19 C = e
# 0.000 0075
molar_gas_constant = 8.3144621 J mol^-1 K^-1 = R
# 0.000 000 0024 e-3
fine_structure_constant = 7.2973525698e-3
# 0.000 000 27 e23
avogadro_number = 6.02214129e23 mol^-1 =N_A
# 0.000 0013 e-23
boltzmann_constant = 1.3806488e-23 J K^-1 = k
# 0.000 021 e-8
stefan_boltzmann_constant = 5.670373e-8 W m^-2 K^-4 = σ
# 0.000 0053 e10
wien_frequency_displacement_law_constant = 5.8789254e10 Hz K^-1
# 0.000 055
rydberg_constant = 10973731.568539 m^-1
# 0.000 000 40 e-31
electron_mass = 9.10938291e-31 kg = m_e
# 0.000 000 074 e-27
neutron_mass = 1.674927351e-27 kg = m_n
# 0.000 000 074 e-27
proton_mass = 1.672621777e-27 kg = m_p
This diff is collapsed.
import os
import json
from cp2kparser.implementation.parser import CP2KParser
import sys
#===============================================================================
......@@ -23,16 +24,17 @@ def scan_path_for_files(path):
#===============================================================================
def get_parser(path, test=True):
def get_parser(path, test_mode=True, stream=sys.stdout):
files = scan_path_for_files(path)
json_input = {
"version": "nomadparsein.json 1.0",
"tmpDir": "/home/lauri",
"metaInfoFile": os.path.join(os.path.dirname(__file__), 'metainfo.json'),
"tmpDir": "/home",
"metainfoToKeep": [],
"metainfoToSkip": [],
"files": files
}
parser = CP2KParser(json.dumps(json_input), test=test)
parser = CP2KParser(json.dumps(json_input), test_mode=test_mode, stream=stream)
return parser
......
This diff is collapsed.
......@@ -23,10 +23,10 @@ class CP2KParser(NomadParser):
implementation. For other versions there should be classes that extend from
this.
"""
def __init__(self, input_json_string, stream=sys.stdout, test=False):
def __init__(self, input_json_string, stream=sys.stdout, test_mode=False):
# Initialize the base class
NomadParser.__init__(self, input_json_string, stream, test)
NomadParser.__init__(self, input_json_string, stream, test_mode)
# Engines are created here
self.csvengine = CSVEngine(self)
......@@ -36,6 +36,7 @@ class CP2KParser(NomadParser):
self.atomsengine = AtomsEngine(self)
self.version_number = None
self.implementation = None
self.input_tree = None
self.regexs = None
......@@ -44,6 +45,18 @@ class CP2KParser(NomadParser):
self.setup_version()
self.determine_file_ids_post_setup()
def get_supported_quantities(self):
"""Inherited from NomadParser.
"""
supported_quantities = []
implementation_methods = [method for method in dir(self.implementation) if callable(getattr(self.implementation, method))]
for method in implementation_methods:
if method.startswith("_Q_"):
method = method[3:]
supported_quantities.append(method)
return supported_quantities
def setup_version(self):
"""Inherited from NomadParser.
"""
......@@ -75,6 +88,16 @@ class CP2KParser(NomadParser):
logger.debug("Using default implementation.")
self.implementation = globals()["CP2KImplementation"](self)
def start_parsing(self, name):
"""Inherited from NomadParser.
"""
# Ask the implementation for the quantity
function = getattr(self.implementation, "_Q_" + name)
if function:
return function()
else:
logger.error("The function for quantity '{}' is not defined".format(name))
def read_part_of_file(self, file_id, size=1024):
fh = self.get_file_handle(file_id)
buffer = fh.read(size)
......@@ -156,8 +179,9 @@ class CP2KParser(NomadParser):
the path until only one or zero matches found.
"""
matches = {}
resolvable = [x for x in self.files.iterkeys() if x not in self.file_ids.itervalues()]
for file_path in self.resolvable:
for file_path in resolvable:
available_parts = self.split_path(file_path)
searched_parts = self.split_path(path)
for i_part, part in enumerate(searched_parts):
......@@ -193,22 +217,10 @@ class CP2KParser(NomadParser):
return folders
def start_parsing(self, name):
"""Inherited from NomadParser. The timing and caching is already
implemented in the superclass.
"""
# Ask the implementation for the quantity
function = getattr(self.implementation, "_Q_" + name)
if function:
return function()
else:
logger.error("The function for quantity '{}' is not defined".format(name))
def check_quantity_availability(self, name):
"""Inherited from NomadParser.
"""
#TODO
return True
def get_all_quantities(self):
"""Parse all supported quantities."""
for method in self.get_supported_quantities:
self.get_quantity(method)
#===============================================================================
......@@ -231,6 +243,25 @@ class CP2KImplementation(object):
self.atomsengine = parser.atomsengine
self.input_tree = parser.input_tree
def decode_cp2k_unit(self, unit):
"""Given a CP2K unit name, decode it as Pint unit definition.
"""
map = {
# Length
"bohr": ureg.bohr,
"m": ureg.meter,
"pm": ureg.picometer,
"nm": ureg.nanometer,
"angstrom": ureg.angstrom,
}
pint_unit = map.get(unit)
if pint_unit:
return pint_unit
else:
logger.error("Unknown CP2K unit definition given.")
def _Q_energy_total(self):
"""Return the total energy from the bottom of the input file"""
result = Result()
......@@ -348,26 +379,13 @@ class CP2KImplementation(object):
force_array[i_conf, :, :] = i_force_array
i_conf += 1
result.value = force_array
result.value_iterable = force_array
return result
else:
logger.debug("Looking for forces in separate force file.")
iterator = self.csvengine.iread(self.parser.get_file_handle("forces"), columns=(-3, -2, -1), comments=("#", "SUM"), separator=r"\ ATOMIC FORCES in \[a\.u\.\]")
forces = []
for configuration in iterator:
forces.append(configuration)
forces = np.array(forces)
if forces is None:
msg = "No force configurations were found when searching an external XYZ force file."
logger.warning(msg)
result.error_message = msg
result.code = ResultCode.fail
return result
else:
if len(forces) != 0:
result.value = forces
return result
result.value_iterable = iterator
return result
def _Q_particle_number(self):
"""Return the number of particles in the system.
......@@ -413,13 +431,15 @@ class CP2KImplementation(object):
return result
def _Q_particle_position(self):
"""Returns the particle positions (trajectory). Currently returns them
as one big object, which is not good because the trajectory can be very
large. When the streaming interface is available the coordinates can be
streamed to an outputfile.
"""Returns the particle positions (trajectory).
"""
result = Result()
# Determine the unit
unit = self.input_tree.get_keyword("MOTION/PRINT/TRAJECTORY/UNIT")
unit = unit.lower()
result.unit = self.decode_cp2k_unit(unit)
# Read the trajectory
traj_file = self.parser.get_file_handle("trajectory")
file_format = self.input_tree.get_keyword("MOTION/PRINT/TRAJECTORY/FORMAT")
......@@ -429,13 +449,8 @@ class CP2KImplementation(object):
}[file_format]
traj_iter = self.atomsengine.iread(traj_file, format=file_format)
# Loop through the iterator to get all configurations
positions = []
for configuration in traj_iter:
positions.append(configuration)
if positions:
result.value = np.array(positions)
# Return the iterator
result.value_iterable = traj_iter
return result
......
......@@ -5,13 +5,15 @@ from cp2kparser.implementation.autoparser import get_parser
from cp2kparser.engines.cp2kinputenginedata.xmlpreparser import *
import cProfile
import pstats
import cStringIO
#===============================================================================
def getparser(folder):
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.join(path, folder)
parser = get_parser(path, test=True)
dump = cStringIO.StringIO()
parser = get_parser(path, test_mode=True, stream=dump)
return parser
......@@ -22,7 +24,7 @@ class TestFunctionals(unittest.TestCase):
path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "functionals", folder)
parser = getparser(path)
xc = parser.parse_quantity("XC_functional")
self.assertEqual(xc.value, result)
self.assertEqual(xc, result)
def test_pade(self):
self.getxc("pade", "LDA_XC_TETER93")
......@@ -42,7 +44,7 @@ class TestForces(unittest.TestCase):
def test_forces_in_outputfile_n(self):
parser = getparser("forces/outputfile/n")
forces = parser.parse_quantity("particle_forces").value
forces = parser.parse_quantity("particle_forces")
n_conf = forces.shape[0]
n_particles = forces.shape[1]
n_dim = forces.shape[2]
......@@ -52,7 +54,7 @@ class TestForces(unittest.TestCase):
def test_forces_in_outputfile_1(self):
parser = getparser("forces/outputfile/1")
forces = parser.parse_quantity("particle_forces").value
forces = parser.parse_quantity("particle_forces")
n_conf = forces.shape[0]
n_particles = forces.shape[1]
n_dim = forces.shape[2]
......@@ -62,12 +64,12 @@ class TestForces(unittest.TestCase):
def test_forces_in_outputfile_0(self):
parser = getparser("forces/outputfile/0")
forces = parser.parse_quantity("particle_forces").value
forces = parser.parse_quantity("particle_forces")
self.assertEqual(forces, None)
def test_forces_in_singlexyzfile_n(self):
parser = getparser("forces/singlexyzfile/n")
forces = parser.parse_quantity("particle_forces").value
forces = parser.parse_quantity("particle_forces")
n_conf = forces.shape[0]
n_particles = forces.shape[1]
n_dim = forces.shape[2]
......@@ -77,7 +79,7 @@ class TestForces(unittest.TestCase):
def test_forces_in_singlexyzfile_1(self):
parser = getparser("forces/singlexyzfile/1")
forces = parser.parse_quantity("particle_forces").value
forces = parser.parse_quantity("particle_forces")
n_conf = forces.shape[0]
n_particles = forces.shape[1]
n_dim = forces.shape[2]
......@@ -87,7 +89,7 @@ class TestForces(unittest.TestCase):
def test_forces_in_singlexyzfile_0(self):
parser = getparser("forces/singlexyzfile/0")
forces = parser.parse_quantity("particle_forces").value
forces = parser.parse_quantity("particle_forces")
self.assertEqual(forces, None)
......@@ -96,42 +98,42 @@ class TestParticleNumber(unittest.TestCase):
def test_input_n(self):
parser = getparser("particle_number/inputfile/n")
n = parser.parse_quantity("particle_number").value
n = parser.parse_quantity("particle_number")
self.assertEqual(n, 2)
def test_input_1(self):
parser = getparser("particle_number/inputfile/1")
n = parser.parse_quantity("particle_number").value
n = parser.parse_quantity("particle_number")
self.assertEqual(n, 1)
def test_input_extra_lines(self):
parser = getparser("particle_number/inputfile/extra_lines")
n = parser.parse_quantity("particle_number").value
n = parser.parse_quantity("particle_number")
self.assertEqual(n, 2)
def test_input_multiplication(self):
parser = getparser("particle_number/inputfile/multiplication")
n = parser.parse_quantity("particle_number").value
n = parser.parse_quantity("particle_number")
self.assertEqual(n, 12)
def test_xyz_n(self):
parser = getparser("particle_number/xyz/n")
n = parser.parse_quantity("particle_number").value
n = parser.parse_quantity("particle_number")
self.assertEqual(n, 2)
def test_xyz_multiplication(self):
parser = getparser("particle_number/xyz/multiplication")
n = parser.parse_quantity("particle_number").value
n = parser.parse_quantity("particle_number")
self.assertEqual(n, 12)
def test_cif_n(self):
parser = getparser("particle_number/cif/n")
n = parser.parse_quantity("particle_number").value
n = parser.parse_quantity("particle_number")
self.assertEqual(n, 2)
def test_pdb_n(self):
parser = getparser("particle_number/pdb/n")
n = parser.parse_quantity("particle_number").value
n = parser.parse_quantity("particle_number")
self.assertEqual(n, 2)
......@@ -140,7 +142,7 @@ class TestTrajectory(unittest.TestCase):
def test_filenames_bare(self):
parser = getparser("trajectory/filenames/bare")
pos = parser.parse_quantity("particle_position").value
pos = parser.parse_quantity("particle_position")
n_conf = pos.shape[0]
n_particles = pos.shape[1]
n_dim = pos.shape[2]
......@@ -150,7 +152,7 @@ class TestTrajectory(unittest.TestCase):
def test_filenames_dotslash(self):
parser = getparser("trajectory/filenames/dotslash")
pos = parser.parse_quantity("particle_position").value
pos = parser.parse_quantity("particle_position")
n_conf = pos.shape[0]
n_particles = pos.shape[1]
n_dim = pos.shape[2]
......@@ -160,7 +162,7 @@ class TestTrajectory(unittest.TestCase):
def test_filenames_equals(self):
parser = getparser("trajectory/filenames/equals")
pos = parser.parse_quantity("particle_position").value
pos = parser.parse_quantity("particle_position")
n_conf = pos.shape[0]
n_particles = pos.shape[1]
n_dim = pos.shape[2]
......@@ -170,7 +172,7 @@ class TestTrajectory(unittest.TestCase):
def test_pdb(self):
parser = getparser("trajectory/pdb")
pos = parser.parse_quantity("particle_position").value
pos = parser.parse_quantity("particle_position")
n_conf = pos.shape[0]
n_particles = pos.shape[1]
n_dim = pos.shape[2]
......@@ -180,7 +182,7 @@ class TestTrajectory(unittest.TestCase):
def test_xyz(self):
parser = getparser("trajectory/xyz")
pos = parser.parse_quantity("particle_position").value
pos = parser.parse_quantity("particle_position")
n_conf = pos.shape[0]
n_particles = pos.shape[1]
n_dim = pos.shape[2]
......
# Default Pint units definition file
# NomadParser Pint units definition file
# Based on the International System of Units
# decimal prefixes
yocto- = 1e-24 = y-
zepto- = 1e-21 = z-
atto- = 1e-18 = a-
femto- = 1e-15 = f-
pico- = 1e-12 = p-
nano- = 1e-9 = n-
micro- = 1e-6 = u- = µ-
milli- = 1e-3 = m-
centi- = 1e-2 = c-
deci- = 1e-1 = d-
deca- = 1e+1 = da-
hecto- = 1e2 = h-
kilo- = 1e3 = k-
mega- = 1e6 = M-
giga- = 1e9 = G-
tera- = 1e12 = T-
peta- = 1e15 = P-
exa- = 1e18 = E-
zetta- = 1e21 = Z-
yotta- = 1e24 = Y-
# binary_prefixes
kibi- = 2**10 = Ki-
mebi- = 2**20 = Mi-
gibi- = 2**30 = Gi-
tebi- = 2**40 = Ti-
pebi- = 2**50 = Pi-
exbi- = 2**60 = Ei-
zebi- = 2**70 = Zi-
yobi- = 2**80 = Yi-
# SI units
meter = [length] = m = metre
second = [time] = s = sec
ampere = [current] = A = amp
candela = [luminosity] = cd = candle
kilogram = [mass] = kg
mole = [substance] = mol
kelvin = [temperature]; offset: 0 = K = degK
@import constants.txt
# Acceleration
[acceleration] = [length] / [time] ** 2
# Angle
radian = [] = rad
turn = 2 * pi * radian = revolution = cycle = circle
degree = pi / 180 * radian = deg = arcdeg = arcdegree = angular_degree
arcminute = arcdeg / 60 = arcmin = arc_minute = angular_minute
arcsecond = arcmin / 60 = arcsec = arc_second = angular_second
steradian = radian ** 2 = sr
# Area
[area] = [length] ** 2
are = 100 * m**2
barn = 1e-28 * m ** 2 = b
cmil = 5.067075e-10 * m ** 2 = circular_mils
darcy = 9.869233e-13 * m ** 2
acre = 4046.8564224 * m ** 2 = international_acre
hectare = 100 * are = ha
US_survey_acre = 160 * rod ** 2
# Electromagetism
esu = 1 * erg**0.5 * centimeter**0.5 = statcoulombs = statC = franklin = Fr
esu_per_second = 1 * esu / second = statampere
ampere_turn = 1 * A
gilbert = 10 / (4 * pi ) * ampere_turn
coulomb = ampere * second = C
volt = joule / coulomb = V
farad = coulomb / volt = F
ohm = volt / ampere = Ω
siemens = ampere / volt = S = mho
weber = volt * second = Wb
tesla = weber / meter ** 2 = T
henry = weber / ampere = H
elementary_charge = 1.602176487e-19 * coulomb = e
chemical_faraday = 9.64957e4 * coulomb
physical_faraday = 9.65219e4 * coulomb
faraday = 96485.3399 * coulomb = C12_faraday
gamma = 1e-9 * tesla
gauss = 1e-4 * tesla
maxwell = 1e-8 * weber = mx
oersted = 1000 / (4 * pi) * A / m = Oe
statfarad = 1.112650e-12 * farad = statF = stF
stathenry = 8.987554e11 * henry = statH = stH
statmho = 1.112650e-12 * siemens = statS = stS
statohm = 8.987554e11 * ohm
statvolt = 2.997925e2 * volt = statV = stV
unit_pole = 1.256637e-7 * weber
# Energy
[energy] = [force] * [length]
joule = newton * meter = J
erg = dyne * centimeter
btu = 1.05505585262e3 * joule = Btu = BTU = british_thermal_unit
electron_volt = 1.60217653e-19 * J = eV
quadrillion_btu = 10**15 * btu = quad
thm = 100000 * BTU = therm = EC_therm
cal = 4.184 * joule = calorie = thermochemical_calorie
international_steam_table_calorie = 4.1868 * joule
ton_TNT = 4.184e9 * joule = tTNT
US_therm = 1.054804e8 * joule
watt_hour = watt * hour = Wh = watthour
hartree = 4.35974394e-18 * joule = E_h = hartree_energy
# Force
[force] = [mass] * [acceleration]
force_au = hartree / bohr
newton = kilogram * meter / second ** 2 = N
dyne = gram * centimeter / second ** 2 = dyn
force_kilogram = g_0 * kilogram = kgf = kilogram_force = pond
force_gram = g_0 * gram = gf = gram_force
force_ounce = g_0 * ounce = ozf = ounce_force
force_pound = g_0 * lb = lbf = pound_force
force_ton = 2000 * force_pound = ton_force
poundal = lb * feet / second ** 2 = pdl
kip = 1000*lbf
# Frequency
[frequency] = 1 / [time]
hertz = 1 / second = Hz = rps
revolutions_per_minute = revolution / minute = rpm
counts_per_second = count / second = cps
# Heat
#RSI = degK * meter ** 2 / watt
#clo = 0.155 * RSI = clos
#R_value = foot ** 2 * degF * hour / btu
# Information
bit = []
byte = 8 * bit = Bo = octet
baud = bit / second = Bd = bps
# Irradiance
peak_sun_hour = 1000 * watt_hour / meter**2 = PSH
langley = thermochemical_calorie / centimeter**2 = Langley
# Length
angstrom = 1e-10 * meter = Å = ångström = Å
inch = 2.54 * centimeter = in = international_inch = inches = international_inches
foot = 12 * inch = ft = international_foot = feet = international_feet
mile = 5280 * foot = mi = international_mile
yard = 3 * feet = yd = international_yard
mil = inch / 1000 = thou
parsec = 3.08568025e16 * meter = pc
light_year = speed_of_light * julian_year = ly = lightyear
astronomical_unit = 149597870691 * meter = au
nautical_mile = 1.852e3 * meter = nmi
printers_point = 127 * millimeter / 360 = point
printers_pica = 12 * printers_point = pica
US_survey_foot = 1200 * meter / 3937
US_survey_yard = 3 * US_survey_foot
US_survey_mile = 5280 * US_survey_foot = US_statute_mile
rod = 16.5 * US_survey_foot = pole = perch
furlong = 660 * US_survey_foot
fathom = 6 * US_survey_foot
chain = 66 * US_survey_foot
barleycorn = inch / 3
arpentlin = 191.835 * feet
kayser = 1 / centimeter = wavenumber
# Mass
dram = oz / 16 = dr = avoirdupois_dram
ounce = 28.349523125 * gram = oz = avoirdupois_ounce
pound = 0.45359237 * kilogram = lb = avoirdupois_pound
stone = 14 * lb = st
carat = 200 * milligram
grain = 64.79891 * milligram = gr
long_hundredweight = 112 * lb
short_hundredweight = 100 * lb
metric_ton = 1000 * kilogram = t = tonne
pennyweight = 24 * gram = dwt
slug = 14.59390 * kilogram
troy_ounce = 480 * grain = toz = apounce = apothecary_ounce
troy_pound = 12 * toz = tlb = appound = apothecary_pound
drachm = 60 * grain = apdram = apothecary_dram
atomic_mass_unit = 1.660538782e-27 * kilogram = u = amu = dalton = Da
scruple = 20 * grain
bag = 94 * lb
ton = 2000 * lb = short_ton