geooptparser.py 10.2 KB
Newer Older
1
from nomadcore.simple_parser import SimpleMatcher as SM
2
from nomadcore.baseclasses import MainHierarchicalParser
3
from commonmatcher import CommonMatcher
4
5
import cp2kparser.generic.configurationreading
import cp2kparser.generic.csvparsing
6
from nomadcore.caching_backend import CachingLevel
7
import logging
8
import ase.io
9
10
11
12
13
14
15
16
17
18
19
20
logger = logging.getLogger("nomad")


#===============================================================================
class CP2KGeoOptParser(MainHierarchicalParser):
    """Used to parse the CP2K calculation with run types:
        -GEO_OPT/GEOMETRY_OPTIMIZATION
    """
    def __init__(self, file_path, parser_context):
        """
        """
        super(CP2KGeoOptParser, self).__init__(file_path, parser_context)
21
        self.setup_common_matcher(CommonMatcher(parser_context))
22
        self.traj_iterator = None
23

24
25
        #=======================================================================
        # Cached values
26
27
        self.cache_service.add_cache_object("number_of_frames_in_sequence", 0)
        self.cache_service.add_cache_object("frame_sequence_potential_energy", [])
28
29
30
31
32

        #=======================================================================
        # Cache levels
        self.caching_level_for_metaname.update({
            'x_cp2k_optimization_energy': CachingLevel.ForwardAndCache,
33
34
            'x_cp2k_optimization_step_size_convergence_limit': CachingLevel.ForwardAndCache,
            'x_cp2k_section_geometry_optimization_information': CachingLevel.ForwardAndCache,
35
36
37
38
        })

        #=======================================================================
        # SimpleMatchers
39
        self.geo_opt = SM(
40
            " ***                     STARTING GEOMETRY OPTIMIZATION                      ***".replace("*", "\*"),
41
            sections=["section_frame_sequence"],
42
            subMatchers=[
43
44
45
46
                SM( " ***                           CONJUGATE GRADIENTS                           ***".replace("*", "\*"),
                    adHoc=self.adHoc_conjugate_gradient()
                ),
                SM( " --------  Informations at step",
47
                    forwardMatch=True,
48
49
50
                    name="geooptstep",
                    repeats=True,
                    sections=["section_single_configuration_calculation", "section_system"],
51
                    subMatchers=[
52
                        SM( " --------  Informations at step",
53
                            sections=["x_cp2k_section_geometry_optimization_information"],
54
55
56
                            otherMetaInfo=[
                                "atom_positions",
                            ],
57
                            subMatchers=[
58
                                SM( "  Optimization Method        =\s+(?P<x_cp2k_optimization_method>{})".format(self.cm.regex_word)),
59
60
61
                                SM( "  Total Energy               =\s+(?P<x_cp2k_optimization_energy__hartree>{})".format(self.cm.regex_f),
                                    otherMetaInfo=["frame_sequence_potential_energy"]
                                ),
62
63
64
65
                                SM( "  Real energy change         =\s+(?P<x_cp2k_optimization_energy_change__hartree>{})".format(self.cm.regex_f)),
                                SM( "  Decrease in energy         =\s+(?P<x_cp2k_optimization_energy_decrease>{})".format(self.cm.regex_word)),
                                SM( "  Used time                  =\s+(?P<x_cp2k_optimization_used_time>{})".format(self.cm.regex_f)),
                                SM( "  Max. step size             =\s+(?P<x_cp2k_optimization_max_step_size__bohr>{})".format(self.cm.regex_f)),
66
67
68
                                SM( "  Conv. limit for step size  =\s+(?P<x_cp2k_optimization_step_size_convergence_limit__bohr>{})".format(self.cm.regex_f),
                                    otherMetaInfo=["geometry_optimization_geometry_change"]
                                ),
69
70
71
72
                                SM( "  Convergence in step size   =\s+(?P<x_cp2k_optimization_step_size_convergence>{})".format(self.cm.regex_word)),
                                SM( "  RMS step size              =\s+(?P<x_cp2k_optimization_rms_step_size__bohr>{})".format(self.cm.regex_f)),
                                SM( "  Convergence in RMS step    =\s+(?P<x_cp2k_optimization_rms_step_size_convergence>{})".format(self.cm.regex_word)),
                                SM( "  Max. gradient              =\s+(?P<x_cp2k_optimization_max_gradient__bohr_1hartree>{})".format(self.cm.regex_f)),
73
74
75
                                SM( "  Conv. limit for gradients  =\s+(?P<x_cp2k_optimization_gradient_convergence_limit__bohr_1hartree>{})".format(self.cm.regex_f),
                                    otherMetaInfo=["geometry_optimization_threshold_force"]
                                ),
76
77
78
79
80
                                SM( "  Conv. for gradients        =\s+(?P<x_cp2k_optimization_max_gradient_convergence>{})".format(self.cm.regex_word)),
                                SM( "  RMS gradient               =\s+(?P<x_cp2k_optimization_rms_gradient__bohr_1hartree>{})".format(self.cm.regex_f)),
                                SM( "  Conv. in RMS gradients     =\s+(?P<x_cp2k_optimization_rms_gradient_convergence>{})".format(self.cm.regex_word)),
                            ],
                            adHoc=self.adHoc_step()
81
82
                        ),
                    ]
83
84
                ),
                SM( " ***                    GEOMETRY OPTIMIZATION COMPLETED                      ***".replace("*", "\*"),
85
86
87
                    adHoc=self.adHoc_geo_opt_converged(),
                    otherMetaInfo=["geometry_optimization_converged"]
                ),
88
            ],
89
90
91
92
93
94
95
        )

        # Compose root matcher according to the run type. This way the
        # unnecessary regex parsers will not be compiled and searched. Saves
        # computational time.
        self.root_matcher = SM("",
            forwardMatch=True,
96
            sections=["section_run", "section_sampling_method"],
97
            subMatchers=[
98
99
100
101
102
103
                SM( "",
                    forwardMatch=True,
                    sections=["section_method"],
                    subMatchers=[
                        self.cm.header(),
                        self.cm.quickstep(),
104
                    ],
105
                ),
106
107
108
109
110
                self.geo_opt
            ]
        )

    #===========================================================================
111
112
113
114
115
    # onClose triggers
    def onClose_section_frame_sequence(self, backend, gIndex, section):
        self.cache_service.push_value("number_of_frames_in_sequence")
        self.cache_service.push_array_values("frame_sequence_potential_energy")

116
117
118
119
120
121
122
123
124
125
126
127
128
        opt_section = section["x_cp2k_section_geometry_optimization_information"]
        if opt_section is not None:
            opt_section = opt_section[-1]
            geo_limit = opt_section["x_cp2k_optimization_step_size_convergence_limit"]
            if geo_limit is not None:
                self.backend.addValue("geometry_optimization_geometry_change", geo_limit[0])
            force_limit = opt_section["x_cp2k_optimization_gradient_convergence_limit"]
            if force_limit is not None:
                self.backend.addValue("geometry_optimization_threshold_force", force_limit[0])

    def onClose_section_sampling_method(self, backend, gIndex, section):
        self.backend.addValue("sampling_method", "geometry_optimization")

129
130
131
    def onClose_x_cp2k_section_geometry_optimization_information(self, backend, gIndex, section):
        energy = section["x_cp2k_optimization_energy"][0]
        self.cache_service["frame_sequence_potential_energy"].append(energy)
132

133
134
    def onClose_section_method(self, backend, gIndex, section):
        traj_file = self.file_service.get_file_by_id("trajectory")
135
136
137
138
139
140
141
142
143
144
145
        traj_format = self.cache_service["trajectory_format"]
        if traj_format is not None and traj_file is not None:

            # Use special parsing for CP2K pdb files because they don't follow the proper syntax
            if traj_format == "PDB":
                self.traj_iterator = cp2kparser.generic.csvparsing.iread(traj_file, columns=[3, 4, 5], start="CRYST", end="END")
            else:
                try:
                    self.traj_iterator = cp2kparser.generic.configurationreading.iread(traj_file)
                except ValueError:
                    pass
146

147
    #===========================================================================
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
    # adHoc functions
    def adHoc_geo_opt_converged(self):
        """Called when the geometry optimization converged.
        """
        def wrapper(parser):
            parser.backend.addValue("geometry_optimization_converged", True)
        return wrapper

    def adHoc_geo_opt_not_converged(self):
        """Called when the geometry optimization did not converge.
        """
        def wrapper(parser):
            parser.backend.addValue("geometry_optimization_converged", False)
        return wrapper

163
164
165
166
167
168
169
    def adHoc_conjugate_gradient(self):
        """Called when conjugate gradient method is used.
        """
        def wrapper(parser):
            parser.backend.addValue("geometry_optimization_method", "conjugate_gradient")
        return wrapper

170
    def adHoc_step(self):
171
172
        """Called when all the step information has been retrieved from the
        output file. Here further information is gathered from external files.
173
174
175
        """
        def wrapper(parser):
            self.cache_service["number_of_frames_in_sequence"] += 1
176
177
178

            # Get the next position from the trajectory file
            if self.traj_iterator is not None:
179
180
181
182
183
184
185
186
                # pos = next(self.traj_iterator)
                # self.cache_service["atom_positions"] = pos
                try:
                    pos = next(self.traj_iterator)
                except StopIteration:
                    logger.error("Could not get the next geometries from an external file. It seems that the number of optimization steps in the CP2K outpufile doesn't match the number of steps found in the external trajectory file.")
                else:
                    self.cache_service["atom_positions"] = pos
187
188
189
190
191

        return wrapper

    def adHoc_setup_traj_file(self):
        def wrapper(parser):
192
            pass
193
194
195
196
197
        return wrapper

    def debug(self):
        def wrapper(parser):
            print "FOUND"
198
        return wrapper