From d0815e09ed5ee0575ed00320fd6df0b7a5906fe1 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Wed, 26 Apr 2017 22:29:32 -0400 Subject: [PATCH 1/9] Fix various code issues in log.py - remove mix of tabs and spaces - improve Python 3 compatibility --- src/log.py | 71 +++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/src/log.py b/src/log.py index aeca1d8..a99e030 100644 --- a/src/log.py +++ b/src/log.py @@ -5,6 +5,7 @@ # 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. +from __future__ import print_function # log tool @@ -28,7 +29,7 @@ nlen = l.nlen length of each vectors names = l.names list of vector names t,pe,... = l.get("Time","KE",...) return one or more vectors of values -l.write("file.txt") write all vectors to a file +l.write("file.txt") write all vectors to a file l.write("file.txt","Time","PE",...) write listed vectors to a file get and write allow abbreviated (uniquely) vector names @@ -76,14 +77,14 @@ def __init__(self,*list): self.flist = [] for word in words: self.flist += glob.glob(word) if len(self.flist) == 0 and len(list) == 1: - raise StandardError,"no log file specified" + raise Exception("no log file specified") if len(list) == 1: self.increment = 0 self.read_all() else: if len(self.flist) > 1: - raise StandardError,"can only incrementally read one log file" + raise Exception("can only incrementally read one log file") self.increment = 1 self.eof = 0 @@ -92,24 +93,24 @@ def __init__(self,*list): def read_all(self): self.read_header(self.flist[0]) - if self.nvec == 0: raise StandardError,"log file has no values" + if self.nvec == 0: raise Exception("log file has no values") # read all files for file in self.flist: self.read_one(file) - print + print() # sort entries by timestep, cull duplicates self.data.sort(self.compare) self.cull() self.nlen = len(self.data) - print "read %d log entries" % self.nlen + print("read %d log entries" % self.nlen) # -------------------------------------------------------------------- def next(self): - if not self.increment: raise StandardError,"cannot read incrementally" + if not self.increment: raise Exception("cannot read incrementally") if self.nvec == 0: try: open(self.flist[0],'r') @@ -124,7 +125,7 @@ def next(self): def get(self,*keys): if len(keys) == 0: - raise StandardError, "no log vectors specified" + raise Exception("no log vectors specified") map = [] for key in keys: @@ -133,18 +134,18 @@ def get(self,*keys): else: count = 0 for i in range(self.nvec): - if self.names[i].find(key) == 0: - count += 1 - index = i + if self.names[i].find(key) == 0: + count += 1 + index = i if count == 1: map.append(index) else: - raise StandardError, "unique log vector %s not found" % key + raise Exception("unique log vector %s not found" % key) vecs = [] for i in range(len(keys)): vecs.append(self.nlen * [0]) - for j in xrange(self.nlen): + for j in range(self.nlen): vecs[i][j] = self.data[j][map[i]] if len(keys) == 1: return vecs[0] @@ -161,21 +162,21 @@ def write(self,filename,*keys): else: count = 0 for i in range(self.nvec): - if self.names[i].find(key) == 0: - count += 1 - index = i + if self.names[i].find(key) == 0: + count += 1 + index = i if count == 1: map.append(index) else: - raise StandardError, "unique log vector %s not found" % key + raise Exception("unique log vector %s not found" % key) else: map = range(self.nvec) f = open(filename,"w") - for i in xrange(self.nlen): - for j in xrange(len(map)): - print >>f,self.data[i][map[j]], - print >>f + for i in range(self.nlen): + for j in range(len(map)): + print(self.data[i][map[j]], end='', file=f) + print(file=f) f.close() # -------------------------------------------------------------------- @@ -226,17 +227,16 @@ def read_header(self,file): keywords.insert(0,"Step") i = 0 for keyword in keywords: - self.names.append(keyword) + self.names.append(keyword) self.ptr[keyword] = i i += 1 - else: s1 = txt.find(self.firststr) s2 = txt.find("\n",s1) line = txt[s1:s2] words = line.split() for i in range(len(words)): - self.names.append(words[i]) + self.names.append(words[i]) self.ptr[words[i]] = i self.nvec = len(self.names) @@ -275,36 +275,36 @@ def read_one(self,*list): if s1 >= 0 and s2 >= 0 and s1 < s2: # found s1,s2 with s1 before s2 if self.style == 2: - s1 = txt.find("\n",s1) + 1 + s1 = txt.find("\n",s1) + 1 elif s1 >= 0 and s2 >= 0 and s2 < s1: # found s1,s2 with s2 before s1 s1 = 0 elif s1 == -1 and s2 >= 0: # found s2, but no s1 - last = 1 + last = 1 s1 = 0 elif s1 >= 0 and s2 == -1: # found s1, but no s2 last = 1 if self.style == 1: s2 = txt.rfind("\n--",s1) + 1 else: - s1 = txt.find("\n",s1) + 1 + s1 = txt.find("\n",s1) + 1 s2 = txt.rfind("\n",s1) + 1 - eof -= len(txt) - s2 + eof -= len(txt) - s2 elif s1 == -1 and s2 == -1: # found neither # could be end-of-file section - # or entire read was one chunk + # or entire read was one chunk if txt.find("Loop time of",start) == start: # end of file, so exit - eof -= len(txt) - start # reset eof to "Loop" - break + eof -= len(txt) - start # reset eof to "Loop" + break - last = 1 # entire read is a chunk + last = 1 # entire read is a chunk s1 = 0 if self.style == 1: s2 = txt.rfind("\n--",s1) + 1 else: s2 = txt.rfind("\n",s1) + 1 - eof -= len(txt) - s2 - if s1 == s2: break + eof -= len(txt) - s2 + if s1 == s2: break chunk = txt[s1:s2-1] start = s2 @@ -321,7 +321,6 @@ def read_one(self,*list): word2 = re.findall(pat2,section) words = word1 + word2 self.data.append(map(float,words)) - else: lines = chunk.split("\n") for line in lines: @@ -330,7 +329,7 @@ def read_one(self,*list): # print last timestep of chunk - print int(self.data[len(self.data)-1][0]), + print(int(self.data[len(self.data)-1][0]), end='') sys.stdout.flush() return eof From 602672ec6b97ca41602fc00a54108e00cfcbc8f0 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Wed, 26 Apr 2017 23:15:15 -0400 Subject: [PATCH 2/9] Remove GUNZIP dependency and avoid keyword variable names --- src/log.py | 63 ++++++++++++++++++++++-------------------------------- 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/src/log.py b/src/log.py index a99e030..5217a71 100644 --- a/src/log.py +++ b/src/log.py @@ -54,10 +54,7 @@ # Imports and external programs import sys, re, glob -from os import popen - -try: tmp = PIZZA_GUNZIP -except: PIZZA_GUNZIP = "gunzip" +import gzip # Class definition @@ -102,7 +99,7 @@ def read_all(self): # sort entries by timestep, cull duplicates - self.data.sort(self.compare) + self.data.sort(key=lambda x: x[0]) self.cull() self.nlen = len(self.data) print("read %d log entries" % self.nlen) @@ -127,10 +124,10 @@ def get(self,*keys): if len(keys) == 0: raise Exception("no log vectors specified") - map = [] + m = [] for key in keys: if self.ptr.has_key(key): - map.append(self.ptr[key]) + m.append(self.ptr[key]) else: count = 0 for i in range(self.nvec): @@ -138,7 +135,7 @@ def get(self,*keys): count += 1 index = i if count == 1: - map.append(index) + m.append(index) else: raise Exception("unique log vector %s not found" % key) @@ -146,7 +143,7 @@ def get(self,*keys): for i in range(len(keys)): vecs.append(self.nlen * [0]) for j in range(self.nlen): - vecs[i][j] = self.data[j][map[i]] + vecs[i][j] = self.data[j][m[i]] if len(keys) == 1: return vecs[0] else: return vecs @@ -155,10 +152,10 @@ def get(self,*keys): def write(self,filename,*keys): if len(keys): - map = [] + m = [] for key in keys: if self.ptr.has_key(key): - map.append(self.ptr[key]) + m.append(self.ptr[key]) else: count = 0 for i in range(self.nvec): @@ -166,31 +163,21 @@ def write(self,filename,*keys): count += 1 index = i if count == 1: - map.append(index) + m.append(index) else: raise Exception("unique log vector %s not found" % key) else: - map = range(self.nvec) + m = list(range(self.nvec)) f = open(filename,"w") for i in range(self.nlen): - for j in range(len(map)): - print(self.data[i][map[j]], end='', file=f) + for x in m: + print(self.data[i][x], end='', file=f) print(file=f) f.close() # -------------------------------------------------------------------- - def compare(self,a,b): - if a[0] < b[0]: - return -1 - elif a[0] > b[0]: - return 1 - else: - return 0 - - # -------------------------------------------------------------------- - def cull(self): i = 1 while i < len(self.data): @@ -199,14 +186,14 @@ def cull(self): # -------------------------------------------------------------------- - def read_header(self,file): + def read_header(self,filename): str_multi = "----- Step" str_one = "Step " - if file[-3:] == ".gz": - txt = popen("%s -c %s" % (PIZZA_GUNZIP,file),'r').read() + if filename[-3:] == ".gz": + txt = gzip.open(filename, 'rt').read() else: - txt = open(file).read() + txt = open(filename, 'rt').read() if txt.find(str_multi) >= 0: self.firststr = str_multi @@ -243,20 +230,20 @@ def read_header(self,file): # -------------------------------------------------------------------- - def read_one(self,*list): + def read_one(self,*args): # if 2nd arg exists set file ptr to that value # read entire (rest of) file into txt - file = list[0] - if file[-3:] == ".gz": - f = popen("%s -c %s" % (PIZZA_GUNZIP,file),'rb') + filename = args[0] + if filename[-3:] == ".gz": + f = gzip.open(filename, 'rt') else: - f = open(file,'rb') + f = open(filename,'rt') - if len(list) == 2: f.seek(list[1]) + if len(args) == 2: f.seek(args[1]) txt = f.read() - if file[-3:] == ".gz": eof = 0 + if filename[-3:] == ".gz": eof = 0 else: eof = f.tell() f.close() @@ -320,12 +307,12 @@ def read_one(self,*list): word1 = [re.search(pat1,section).group(1)] word2 = re.findall(pat2,section) words = word1 + word2 - self.data.append(map(float,words)) + self.data.append(list(map(float,words))) else: lines = chunk.split("\n") for line in lines: words = line.split() - self.data.append(map(float,words)) + self.data.append(list(map(float,words))) # print last timestep of chunk From 349ed48d81c5602b424b8fa17dcd0dbec6ff72cb Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Thu, 27 Apr 2017 00:12:20 -0400 Subject: [PATCH 3/9] Start process of converting Pizza.py into standard Python package --- .gitignore | 1 + pizza/__init__.py | 0 {src => pizza}/log.py | 13 +++++-------- setup.py | 15 +++++++++++++++ tests/test_log.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 .gitignore create mode 100644 pizza/__init__.py rename {src => pizza}/log.py (97%) create mode 100644 setup.py create mode 100644 tests/test_log.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/pizza/__init__.py b/pizza/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/log.py b/pizza/log.py similarity index 97% rename from src/log.py rename to pizza/log.py index 5217a71..c1f99e4 100644 --- a/src/log.py +++ b/pizza/log.py @@ -126,7 +126,7 @@ def get(self,*keys): m = [] for key in keys: - if self.ptr.has_key(key): + if key in self.ptr: m.append(self.ptr[key]) else: count = 0 @@ -154,7 +154,7 @@ def write(self,filename,*keys): if len(keys): m = [] for key in keys: - if self.ptr.has_key(key): + if key in self.ptr: m.append(self.ptr[key]) else: count = 0 @@ -169,12 +169,9 @@ def write(self,filename,*keys): else: m = list(range(self.nvec)) - f = open(filename,"w") - for i in range(self.nlen): - for x in m: - print(self.data[i][x], end='', file=f) - print(file=f) - f.close() + with open(filename,"w") as f: + for i in range(self.nlen): + print(' '.join(map(str, [self.data[i][x] for x in m])), file=f) # -------------------------------------------------------------------- diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..6552a91 --- /dev/null +++ b/setup.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +from distutils.core import setup + +setup(name='Pizza.py', + version='1.0', + description='Pizza.py is a loosely integrated collection of tools written in Python, many of which provide pre- ' + 'and post-processing capability for the LAMMPS molecular dynamics package. There are tools to create ' + 'input files, convert between file formats, process log and dump files, create plots, and visualize ' + 'and animate simulation snapshots.', + author='Steve Plimpton', + author_email='sjplimp@sandia.gov', + url='http://pizza.sandia.gov/', + packages=['pizza'], + ) \ No newline at end of file diff --git a/tests/test_log.py b/tests/test_log.py new file mode 100644 index 0000000..98f7d0b --- /dev/null +++ b/tests/test_log.py @@ -0,0 +1,43 @@ +import unittest +import csv +import os +from pizza.log import log + + +class TestLog(unittest.TestCase): + EXAMPLE_FILE = "../examples/files/log.obstacle" + + def test_read_log(self): + lg = log(TestLog.EXAMPLE_FILE) + self.assertEqual(lg.nvec, 7) + self.assertEqual(lg.nlen, 26) + self.assertListEqual(lg.names, ["Step", "Temperature", "E_pair", "E_bond", "E_total", "Pressure", "Volume"]) + + def test_log_get(self): + lg = log(TestLog.EXAMPLE_FILE) + time, temp, press = lg.get("Step", "Temp", "Press") + self.assertEqual(len(time), 26) + self.assertEqual(len(temp), 26) + self.assertEqual(len(press), 26) + + def test_write_all(self): + tmp_file = "/tmp/tmp.log" + lg = log(TestLog.EXAMPLE_FILE) + lg.write(tmp_file) + self.assertTrue(os.path.exists(tmp_file)) + + with open(tmp_file, 'rt') as csvfile: + lines = list(csv.reader(csvfile, delimiter=' ')) + self.assertEqual(len(lines), 26) + self.assertEqual(len(lines[0]), 7) + + def test_write_columns(self): + tmp_file = "/tmp/tmp.log.two" + lg = log(TestLog.EXAMPLE_FILE) + lg.write(tmp_file, "Step", "E_pair") + self.assertTrue(os.path.exists(tmp_file)) + + with open(tmp_file, 'rt') as csvfile: + lines = list(csv.reader(csvfile, delimiter=' ')) + self.assertEqual(len(lines), 26) + self.assertEqual(len(lines[0]), 2) From 3bab5a0782945edb537d943a46662797dc784ae8 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Thu, 27 Apr 2017 00:49:48 -0400 Subject: [PATCH 4/9] Use more compact syntax --- pizza/log.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pizza/log.py b/pizza/log.py index c1f99e4..a720ed0 100644 --- a/pizza/log.py +++ b/pizza/log.py @@ -171,7 +171,7 @@ def write(self,filename,*keys): with open(filename,"w") as f: for i in range(self.nlen): - print(' '.join(map(str, [self.data[i][x] for x in m])), file=f) + print(*[self.data[i][x] for x in m], file=f) # -------------------------------------------------------------------- From 424d88faa0746e35a0e31c7777d5bbb50ad761d0 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Sun, 30 Apr 2017 21:14:32 -0400 Subject: [PATCH 5/9] Skip lines which contain alphabet characters while parsing thermo data --- pizza/log.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pizza/log.py b/pizza/log.py index a720ed0..225d671 100644 --- a/pizza/log.py +++ b/pizza/log.py @@ -307,7 +307,9 @@ def read_one(self,*args): self.data.append(list(map(float,words))) else: lines = chunk.split("\n") + alpha = re.compile('[a-zA-Z]') for line in lines: + if alpha.search(line): continue words = line.split() self.data.append(list(map(float,words))) From 4db5986b344bdae23345022e5d2b4486008fec92 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Sun, 30 Apr 2017 22:07:34 -0400 Subject: [PATCH 6/9] Don't skip lines with floats in scientific notation --- pizza/log.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pizza/log.py b/pizza/log.py index 225d671..ab6d815 100644 --- a/pizza/log.py +++ b/pizza/log.py @@ -307,7 +307,7 @@ def read_one(self,*args): self.data.append(list(map(float,words))) else: lines = chunk.split("\n") - alpha = re.compile('[a-zA-Z]') + alpha = re.compile('[a-df-zA-DF-Z]') # except e or E for floating-point numbers for line in lines: if alpha.search(line): continue words = line.split() From 426e3cf914a2963efe05ac10fe1b0ff4e0562506 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Mon, 28 Dec 2020 09:23:20 -0500 Subject: [PATCH 7/9] add missing newline --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6552a91..83dc87f 100644 --- a/setup.py +++ b/setup.py @@ -12,4 +12,4 @@ author_email='sjplimp@sandia.gov', url='http://pizza.sandia.gov/', packages=['pizza'], - ) \ No newline at end of file + ) From 644d65ea2a2bad1b41d763958b19f135d56f67c2 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Mon, 28 Dec 2020 11:22:59 -0500 Subject: [PATCH 8/9] Use full path for examples --- tests/test_log.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_log.py b/tests/test_log.py index 98f7d0b..43a2c3a 100644 --- a/tests/test_log.py +++ b/tests/test_log.py @@ -3,9 +3,10 @@ import os from pizza.log import log +TESTS_DIR=os.path.dirname(os.path.abspath(__file__)) class TestLog(unittest.TestCase): - EXAMPLE_FILE = "../examples/files/log.obstacle" + EXAMPLE_FILE = os.path.join(TESTS_DIR, "../examples/files/log.obstacle") def test_read_log(self): lg = log(TestLog.EXAMPLE_FILE) From 0841d00f64d9a2469f8d921df1595c314b2617c5 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Mon, 28 Dec 2020 11:24:25 -0500 Subject: [PATCH 9/9] Fix unclosed file warning --- pizza/log.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pizza/log.py b/pizza/log.py index ab6d815..f0735e9 100644 --- a/pizza/log.py +++ b/pizza/log.py @@ -188,9 +188,11 @@ def read_header(self,filename): str_one = "Step " if filename[-3:] == ".gz": - txt = gzip.open(filename, 'rt').read() + with gzip.open(filename, 'rt') as f: + txt = f.read() else: - txt = open(filename, 'rt').read() + with open(filename, 'rt') as f: + txt = f.read() if txt.find(str_multi) >= 0: self.firststr = str_multi