From 41dcc781aa4fe63380763e9acc100ed82b06a661 Mon Sep 17 00:00:00 2001
From: Lauri Himanen <lauri.himanen@aalto.fi>
Date: Tue, 27 Sep 2016 11:09:08 +0300
Subject: [PATCH] Added modules for vibration and properties calculation, fixed
 issues with global cache having uninitialized values, fixedissues with empty
 MD information.

---
 parser/parser-cpmd/cpmdparser/parser.py       | 12 +++++
 .../versions/cpmd41/commonparser.py           |  5 ++
 .../cpmdparser/versions/cpmd41/inputparser.py |  4 --
 .../cpmdparser/versions/cpmd41/mdparser.py    | 35 +++++++------
 .../versions/cpmd41/propertiesparser.py       | 49 +++++++++++++++++++
 .../versions/cpmd41/vibrationparser.py        | 49 +++++++++++++++++++
 6 files changed, 135 insertions(+), 19 deletions(-)
 create mode 100644 parser/parser-cpmd/cpmdparser/versions/cpmd41/propertiesparser.py
 create mode 100644 parser/parser-cpmd/cpmdparser/versions/cpmd41/vibrationparser.py

diff --git a/parser/parser-cpmd/cpmdparser/parser.py b/parser/parser-cpmd/cpmdparser/parser.py
index de76da8..476bedb 100644
--- a/parser/parser-cpmd/cpmdparser/parser.py
+++ b/parser/parser-cpmd/cpmdparser/parser.py
@@ -38,6 +38,8 @@ class CPMDParser(ParserInterface):
         regex_single_point = re.compile(r" SINGLE POINT DENSITY OPTIMIZATION")
         regex_geo_opt = re.compile(r" OPTIMIZATION OF IONIC POSITIONS")
         regex_md = re.compile(r"( CAR-PARRINELLO MOLECULAR DYNAMICS)|( BORN-OPPENHEIMER MOLECULAR DYNAMICS)")
+        regex_vib = re.compile(r" PERFORM A VIBRATIONAL ANALYSIS BY FINITE DIFFERENCES")
+        regex_prop = re.compile(r" CALCULATE SOME PROPERTIES")
         run_type = None
         n_lines = 1000
         version_id = None
@@ -68,6 +70,16 @@ class CPMDParser(ParserInterface):
                 if result_md:
                     run_type = CPMDRunType(module_name="mdparser", class_name="CPMDMDParser")
 
+                # Look for vibrational analysis
+                result_vib = regex_vib.match(line)
+                if result_vib:
+                    run_type = CPMDRunType(module_name="vibrationparser", class_name="CPMDVibrationParser")
+
+                # Look for properties calculation
+                result_prop = regex_prop.match(line)
+                if result_prop:
+                    run_type = CPMDRunType(module_name="propertiesparser", class_name="CPMDPropertiesParser")
+
         if version_id is None:
             msg = "Could not find a version specification from the given main file."
             logger.exception(msg)
diff --git a/parser/parser-cpmd/cpmdparser/versions/cpmd41/commonparser.py b/parser/parser-cpmd/cpmdparser/versions/cpmd41/commonparser.py
index dfed5c7..718388d 100644
--- a/parser/parser-cpmd/cpmdparser/versions/cpmd41/commonparser.py
+++ b/parser/parser-cpmd/cpmdparser/versions/cpmd41/commonparser.py
@@ -30,6 +30,11 @@ class CPMDCommonParser(CommonParser):
         self.cache_service.add("ensemble_type")
         self.cache_service.add("time_step_ions")
 
+        self.cache_service.add("trajectory_range", False)
+        self.cache_service.add("trajectory_sample", False)
+        self.cache_service.add("print_freq", 1)
+        self.cache_service.add("configuration_periodic_dimensions", single=False, update=False)
+
     #===========================================================================
     # Common SimpleMatchers
     def header(self):
diff --git a/parser/parser-cpmd/cpmdparser/versions/cpmd41/inputparser.py b/parser/parser-cpmd/cpmdparser/versions/cpmd41/inputparser.py
index 6c5f2ee..4535120 100644
--- a/parser/parser-cpmd/cpmdparser/versions/cpmd41/inputparser.py
+++ b/parser/parser-cpmd/cpmdparser/versions/cpmd41/inputparser.py
@@ -16,10 +16,6 @@ class CPMDInputParser(BasicParser):
         """
         super(CPMDInputParser, self).__init__(file_path, parser_context)
         self.input_tree = None
-        self.cache_service.add("trajectory_range", False)
-        self.cache_service.add("trajectory_sample", False)
-        self.cache_service.add("print_freq", 1)
-        self.cache_service.add("configuration_periodic_dimensions", single=False, update=False)
 
     def parse(self):
         self.setup_input_tree(self.parser_context.version_id)
diff --git a/parser/parser-cpmd/cpmdparser/versions/cpmd41/mdparser.py b/parser/parser-cpmd/cpmdparser/versions/cpmd41/mdparser.py
index e016d88..791a2b1 100644
--- a/parser/parser-cpmd/cpmdparser/versions/cpmd41/mdparser.py
+++ b/parser/parser-cpmd/cpmdparser/versions/cpmd41/mdparser.py
@@ -247,19 +247,24 @@ class CPMDMDParser(MainHierarchicalParser):
             self.backend.closeSection("section_system", sys_id)
 
         # Push the summaries
-        potential_energies = np.array(potential_energies)
-        self.backend.addArrayValues("frame_sequence_potential_energy", potential_energies, unit="hartree")
-        kinetic_energies = np.array(kinetic_energies)
-        self.backend.addArrayValues("frame_sequence_kinetic_energy", kinetic_energies, unit="hartree")
-        conserved_quantities = np.array(conserved_quantities)
-        self.backend.addArrayValues("frame_sequence_conserved_quantity", conserved_quantities, unit="hartree")
-        temperatures = np.array(temperatures)
-        self.backend.addArrayValues("frame_sequence_temperature", temperatures, unit="K")
+        if potential_energies:
+            potential_energies = np.array(potential_energies)
+            self.backend.addArrayValues("frame_sequence_potential_energy", potential_energies, unit="hartree")
+        if kinetic_energies:
+            kinetic_energies = np.array(kinetic_energies)
+            self.backend.addArrayValues("frame_sequence_kinetic_energy", kinetic_energies, unit="hartree")
 
-        # Push the statistics. CPMD prints some statistics at the end, but the
-        # mean and std of kinetic energy are missing
-        kin_mean = kinetic_energies.mean()
-        kin_temp = (kinetic_energies - kin_mean)
-        kin_std = np.sqrt(np.dot(kin_temp, kin_temp)/kinetic_energies.size)
-        kin_temp = None
-        self.backend.addArrayValues("frame_sequence_kinetic_energy_stats", np.array([kin_mean, kin_std]), unit="hartree")
+            # Push the statistics. CPMD prints some statistics at the end, but the
+            # mean and std of kinetic energy are missing
+            kin_mean = kinetic_energies.mean()
+            kin_temp = (kinetic_energies - kin_mean)
+            kin_std = np.sqrt(np.dot(kin_temp, kin_temp)/kinetic_energies.size)
+            kin_temp = None
+            self.backend.addArrayValues("frame_sequence_kinetic_energy_stats", np.array([kin_mean, kin_std]), unit="hartree")
+
+        if conserved_quantities:
+            conserved_quantities = np.array(conserved_quantities)
+            self.backend.addArrayValues("frame_sequence_conserved_quantity", conserved_quantities, unit="hartree")
+        if temperatures:
+            temperatures = np.array(temperatures)
+            self.backend.addArrayValues("frame_sequence_temperature", temperatures, unit="K")
diff --git a/parser/parser-cpmd/cpmdparser/versions/cpmd41/propertiesparser.py b/parser/parser-cpmd/cpmdparser/versions/cpmd41/propertiesparser.py
new file mode 100644
index 0000000..61b5f10
--- /dev/null
+++ b/parser/parser-cpmd/cpmdparser/versions/cpmd41/propertiesparser.py
@@ -0,0 +1,49 @@
+from __future__ import absolute_import
+from nomadcore.simple_parser import SimpleMatcher as SM
+from nomadcore.baseclasses import MainHierarchicalParser
+import numpy as np
+from .commonparser import CPMDCommonParser
+import re
+import logging
+LOGGER = logging.getLogger("nomad")
+
+
+#===============================================================================
+class CPMDPropertiesParser(MainHierarchicalParser):
+    """The main parser class that is called for all run types. Parses the CPMD
+    output file.
+    """
+    def __init__(self, file_path, parser_context):
+        """
+        """
+        super(CPMDPropertiesParser, self).__init__(file_path, parser_context)
+        self.setup_common_matcher(CPMDCommonParser(parser_context))
+        self.n_frames = 0
+        self.sampling_method_gid = None
+        self.frame_refs = []
+        self.energies = []
+
+        #=======================================================================
+        # Main structure
+        self.root_matcher = SM("",
+            forwardMatch=True,
+            sections=['section_run', "section_method"],
+            subMatchers=[
+                self.cm.header(),
+                self.cm.method(),
+                self.cm.atoms(),
+                self.cm.cell(),
+                self.cm.initialization(),
+                self.cm.footer(),
+            ]
+        )
+
+    #=======================================================================
+    # onClose triggers
+    def onClose_section_system(self, backend, gIndex, section):
+        self.cache_service.addArrayValues("atom_labels")
+        self.cache_service.addArrayValues("simulation_cell", unit="bohr")
+        self.cache_service.addValue("number_of_atoms")
+
+    #=======================================================================
+    # adHoc
diff --git a/parser/parser-cpmd/cpmdparser/versions/cpmd41/vibrationparser.py b/parser/parser-cpmd/cpmdparser/versions/cpmd41/vibrationparser.py
new file mode 100644
index 0000000..93e825c
--- /dev/null
+++ b/parser/parser-cpmd/cpmdparser/versions/cpmd41/vibrationparser.py
@@ -0,0 +1,49 @@
+from __future__ import absolute_import
+from nomadcore.simple_parser import SimpleMatcher as SM
+from nomadcore.baseclasses import MainHierarchicalParser
+import numpy as np
+from .commonparser import CPMDCommonParser
+import re
+import logging
+LOGGER = logging.getLogger("nomad")
+
+
+#===============================================================================
+class CPMDVibrationParser(MainHierarchicalParser):
+    """The main parser class that is called for all run types. Parses the CPMD
+    output file.
+    """
+    def __init__(self, file_path, parser_context):
+        """
+        """
+        super(CPMDVibrationParser, self).__init__(file_path, parser_context)
+        self.setup_common_matcher(CPMDCommonParser(parser_context))
+        self.n_frames = 0
+        self.sampling_method_gid = None
+        self.frame_refs = []
+        self.energies = []
+
+        #=======================================================================
+        # Main structure
+        self.root_matcher = SM("",
+            forwardMatch=True,
+            sections=['section_run', "section_method"],
+            subMatchers=[
+                self.cm.header(),
+                self.cm.method(),
+                self.cm.atoms(),
+                self.cm.cell(),
+                self.cm.initialization(),
+                self.cm.footer(),
+            ]
+        )
+
+    #=======================================================================
+    # onClose triggers
+    def onClose_section_system(self, backend, gIndex, section):
+        self.cache_service.addArrayValues("atom_labels")
+        self.cache_service.addArrayValues("simulation_cell", unit="bohr")
+        self.cache_service.addValue("number_of_atoms")
+
+    #=======================================================================
+    # adHoc
-- 
GitLab