Commit 4961e40b authored by Lauri Himanen's avatar Lauri Himanen
Browse files

Fixed issue with restarted calculations, fixed bugs in reading MD files with...

Fixed issue with restarted calculations, fixed bugs in reading MD files with non-unity print frequencies.
parent d361b1ad
...@@ -32,12 +32,15 @@ class CP2KParser(ParserInterface): ...@@ -32,12 +32,15 @@ class CP2KParser(ParserInterface):
# this information. # this information.
regex_version = re.compile(r" CP2K\| version string:\s+CP2K version ([\d\.]+)") regex_version = re.compile(r" CP2K\| version string:\s+CP2K version ([\d\.]+)")
regex_run_type = re.compile(r"\s+GLOBAL\| Run type\s+(.+)") regex_run_type = re.compile(r"\s+GLOBAL\| Run type\s+(.+)")
n_lines = 50 n_lines = 100
version_id = None version_id = None
run_type = None run_type = None
with open(self.parser_context.main_file, 'r') as outputfile: with open(self.parser_context.main_file, 'r') as outputfile:
for i_line in range(n_lines): for i_line in range(n_lines):
line = next(outputfile) try:
line = next(outputfile)
except StopIteration:
break
result_version = regex_version.match(line) result_version = regex_version.match(line)
result_run_type = regex_run_type.match(line) result_run_type = regex_run_type.match(line)
if result_version: if result_version:
......
...@@ -127,11 +127,28 @@ class CP2KCommonParser(CommonParser): ...@@ -127,11 +127,28 @@ class CP2KCommonParser(CommonParser):
], ],
), ),
SM( " CELL\|", SM( " CELL\|",
adHoc=self.adHoc_x_cp2k_section_cell(), adHoc=self.adHoc_x_cp2k_section_cell,
), ),
] ]
) )
# SimpleMatcher for the restart information
def restart(self):
return SM( re.escape(" * RESTART INFORMATION *"),
sections=["x_cp2k_section_restart_information"],
subMatchers=[
SM( re.escape(" *******************************************************************************")),
SM( re.escape(" * *")),
SM( re.escape(" * RESTART FILE NAME: (?P<x_cp2k_restart_file_name>{})\s+*".format(self.regexs.word))),
SM( re.escape(" * *")),
SM( re.escape(" * RESTARTED QUANTITIES: *")),
SM( re.escape(" * (?P<x_cp2k_restarted_quantity>{})\s+*".format(self.regexs.word)),
repeats=True,
),
SM( re.escape(" *******************************************************************************"))
]
)
# SimpleMatcher for the footer that is common to all run types # SimpleMatcher for the footer that is common to all run types
def footer(self): def footer(self):
return SM( " - DBCSR STATISTICS -", return SM( " - DBCSR STATISTICS -",
...@@ -168,32 +185,32 @@ class CP2KCommonParser(CommonParser): ...@@ -168,32 +185,32 @@ class CP2KCommonParser(CommonParser):
] ]
), ),
SM( r" \*\*\* SCF run converged in\s+(\d+) steps \*\*\*", SM( r" \*\*\* SCF run converged in\s+(\d+) steps \*\*\*",
adHoc=self.adHoc_single_point_converged() adHoc=self.adHoc_single_point_converged
), ),
SM( r" \*\*\* SCF run NOT converged \*\*\*", SM( r" \*\*\* SCF run NOT converged \*\*\*",
adHoc=self.adHoc_single_point_not_converged() adHoc=self.adHoc_single_point_not_converged
), ),
SM( r" Electronic kinetic energy:\s+(?P<x_cp2k_electronic_kinetic_energy__hartree>{})".format(self.regexs.float)), SM( r" Electronic kinetic energy:\s+(?P<x_cp2k_electronic_kinetic_energy__hartree>{})".format(self.regexs.float)),
SM( r" **************************** NUMERICAL STRESS ********************************".replace("*", "\*"), SM( r" **************************** NUMERICAL STRESS ********************************".replace("*", "\*"),
# endReStr=" **************************** NUMERICAL STRESS END *****************************".replace("*", "\*"), # endReStr=" **************************** NUMERICAL STRESS END *****************************".replace("*", "\*"),
adHoc=self.adHoc_stress_calculation(), adHoc=self.adHoc_stress_calculation,
), ),
SM( r" ENERGY\| Total FORCE_EVAL \( \w+ \) energy \(a\.u\.\):\s+(?P<x_cp2k_energy_total__hartree>{0})".format(self.regexs.float), SM( r" ENERGY\| Total FORCE_EVAL \( \w+ \) energy \(a\.u\.\):\s+(?P<x_cp2k_energy_total__hartree>{0})".format(self.regexs.float),
), ),
SM( r" ATOMIC FORCES in \[a\.u\.\]"), SM( r" ATOMIC FORCES in \[a\.u\.\]"),
SM( r" # Atom Kind Element X Y Z", SM( r" # Atom Kind Element X Y Z",
adHoc=self.adHoc_atom_forces(), adHoc=self.adHoc_atom_forces,
), ),
SM( r" (?:NUMERICAL )?STRESS TENSOR \[GPa\]", SM( r" (?:NUMERICAL )?STRESS TENSOR \[GPa\]",
sections=["x_cp2k_section_stress_tensor"], sections=["x_cp2k_section_stress_tensor"],
subMatchers=[ subMatchers=[
SM( r"\s+X\s+Y\s+Z", SM( r"\s+X\s+Y\s+Z",
adHoc=self.adHoc_stress_tensor(), adHoc=self.adHoc_stress_tensor,
), ),
SM( " 1/3 Trace\(stress tensor\):\s+(?P<x_cp2k_stress_tensor_one_third_of_trace__GPa>{})".format(self.regexs.float)), SM( " 1/3 Trace\(stress tensor\):\s+(?P<x_cp2k_stress_tensor_one_third_of_trace__GPa>{})".format(self.regexs.float)),
SM( " Det\(stress tensor\)\s+:\s+(?P<x_cp2k_stress_tensor_determinant__GPa3>{})".format(self.regexs.float)), SM( " Det\(stress tensor\)\s+:\s+(?P<x_cp2k_stress_tensor_determinant__GPa3>{})".format(self.regexs.float)),
SM( " EIGENVECTORS AND EIGENVALUES OF THE STRESS TENSOR", SM( " EIGENVECTORS AND EIGENVALUES OF THE STRESS TENSOR",
adHoc=self.adHoc_stress_tensor_eigenpairs()), adHoc=self.adHoc_stress_tensor_eigenpairs),
] ]
) )
] ]
...@@ -201,7 +218,7 @@ class CP2KCommonParser(CommonParser): ...@@ -201,7 +218,7 @@ class CP2KCommonParser(CommonParser):
# SimpleMatcher the stuff that is done to initialize a quickstep calculation # SimpleMatcher the stuff that is done to initialize a quickstep calculation
def quickstep_header(self): def quickstep_header(self):
return SM( " *******************************************************************************".replace("*", "\*"), return SM( re.escape(" ** ... make the atoms dance **"),
forwardMatch=True, forwardMatch=True,
sections=["x_cp2k_section_quickstep_settings"], sections=["x_cp2k_section_quickstep_settings"],
subMatchers=[ subMatchers=[
...@@ -216,7 +233,7 @@ class CP2KCommonParser(CommonParser): ...@@ -216,7 +233,7 @@ class CP2KCommonParser(CommonParser):
], ],
), ),
SM( " DFT\+U\|", SM( " DFT\+U\|",
adHoc=self.adHoc_dft_plus_u(), adHoc=self.adHoc_dft_plus_u,
), ),
SM( " QS\|", SM( " QS\|",
forwardMatch=True, forwardMatch=True,
...@@ -301,10 +318,10 @@ class CP2KCommonParser(CommonParser): ...@@ -301,10 +318,10 @@ class CP2KCommonParser(CommonParser):
] ]
), ),
SM( " MP2\|", SM( " MP2\|",
adHoc=self.adHoc_mp2() adHoc=self.adHoc_mp2
), ),
SM( " RI-RPA\|", SM( " RI-RPA\|",
adHoc=self.adHoc_rpa() adHoc=self.adHoc_rpa
), ),
] ]
) )
...@@ -501,113 +518,96 @@ class CP2KCommonParser(CommonParser): ...@@ -501,113 +518,96 @@ class CP2KCommonParser(CommonParser):
#=========================================================================== #===========================================================================
# adHoc functions # adHoc functions
def adHoc_x_cp2k_section_cell(self): def adHoc_x_cp2k_section_cell(self, parser):
"""Used to extract the cell information. """Used to extract the cell information.
""" """
def wrapper(parser): # Read the lines containing the cell vectors
# Read the lines containing the cell vectors a_line = parser.fIn.readline()
a_line = parser.fIn.readline() b_line = parser.fIn.readline()
b_line = parser.fIn.readline() c_line = parser.fIn.readline()
c_line = parser.fIn.readline()
# Define the regex that extracts the components and apply it to the lines
# Define the regex that extracts the components and apply it to the lines regex_string = r" CELL\| Vector \w \[angstrom\]:\s+({0})\s+({0})\s+({0})".format(self.regexs.float)
regex_string = r" CELL\| Vector \w \[angstrom\]:\s+({0})\s+({0})\s+({0})".format(self.regexs.float) regex_compiled = re.compile(regex_string)
regex_compiled = re.compile(regex_string) a_result = regex_compiled.match(a_line)
a_result = regex_compiled.match(a_line) b_result = regex_compiled.match(b_line)
b_result = regex_compiled.match(b_line) c_result = regex_compiled.match(c_line)
c_result = regex_compiled.match(c_line)
# Convert the string results into a 3x3 numpy array
# Convert the string results into a 3x3 numpy array cell = np.zeros((3, 3))
cell = np.zeros((3, 3)) cell[0, :] = [float(x) for x in a_result.groups()]
cell[0, :] = [float(x) for x in a_result.groups()] cell[1, :] = [float(x) for x in b_result.groups()]
cell[1, :] = [float(x) for x in b_result.groups()] cell[2, :] = [float(x) for x in c_result.groups()]
cell[2, :] = [float(x) for x in c_result.groups()]
# Push the results to cache
# Push the results to cache self.cache_service["simulation_cell"] = cell
self.cache_service["simulation_cell"] = cell
return wrapper def adHoc_atom_forces(self, parser):
def adHoc_atom_forces(self):
"""Used to extract the final atomic forces printed at the end of a """Used to extract the final atomic forces printed at the end of a
calculation. calculation.
""" """
def wrapper(parser): end_str = " SUM OF ATOMIC FORCES"
end = False
end_str = " SUM OF ATOMIC FORCES" force_array = []
end = False
force_array = [] # Loop through coordinates until the sum of forces is read
while not end:
# Loop through coordinates until the sum of forces is read line = parser.fIn.readline()
while not end: if line.startswith(end_str):
line = parser.fIn.readline() end = True
if line.startswith(end_str): else:
end = True forces = line.split()[-3:]
else: forces = [float(x) for x in forces]
forces = line.split()[-3:] force_array.append(forces)
forces = [float(x) for x in forces] force_array = np.array(force_array)
force_array.append(forces)
force_array = np.array(force_array)
# If anything found, push the results to the correct section
if len(force_array) != 0:
# self.cache_service["atom_forces"] = force_array
self.backend.addArrayValues("x_cp2k_atom_forces", force_array, unit="forceAu")
return wrapper # If anything found, push the results to the correct section
if len(force_array) != 0:
# self.cache_service["atom_forces"] = force_array
self.backend.addArrayValues("x_cp2k_atom_forces", force_array, unit="forceAu")
def adHoc_stress_tensor(self): def adHoc_stress_tensor(self, parser):
"""Used to extract the stress tensor printed at the end of a """Used to extract the stress tensor printed at the end of a
calculation. calculation.
""" """
def wrapper(parser): row1 = [float(x) for x in parser.fIn.readline().split()[-3:]]
row1 = [float(x) for x in parser.fIn.readline().split()[-3:]] row2 = [float(x) for x in parser.fIn.readline().split()[-3:]]
row2 = [float(x) for x in parser.fIn.readline().split()[-3:]] row3 = [float(x) for x in parser.fIn.readline().split()[-3:]]
row3 = [float(x) for x in parser.fIn.readline().split()[-3:]] stress_array = np.array([row1, row2, row3])
stress_array = np.array([row1, row2, row3]) parser.backend.addArrayValues("x_cp2k_stress_tensor", stress_array, unit="GPa")
parser.backend.addArrayValues("x_cp2k_stress_tensor", stress_array, unit="GPa")
return wrapper
def adHoc_stress_calculation(self): def adHoc_stress_calculation(self, parser):
"""Used to skip over the stress tensor calculation details. """Used to skip over the stress tensor calculation details.
""" """
def wrapper(parser): end_line = " **************************** NUMERICAL STRESS END *****************************\n"
end_line = " **************************** NUMERICAL STRESS END *****************************\n" finished = False
finished = False while not finished:
while not finished: line = parser.fIn.readline()
line = parser.fIn.readline() if line == end_line:
if line == end_line: finished = True
finished = True
return wrapper def adHoc_stress_tensor_eigenpairs(self, parser):
def adHoc_stress_tensor_eigenpairs(self):
"""Parses the stress tensor eigenpairs. """Parses the stress tensor eigenpairs.
""" """
def wrapper(parser): parser.fIn.readline()
parser.fIn.readline() eigenvalues = np.array([float(x) for x in parser.fIn.readline().split()])
eigenvalues = np.array([float(x) for x in parser.fIn.readline().split()]) parser.fIn.readline()
parser.fIn.readline() row1 = [float(x) for x in parser.fIn.readline().split()]
row1 = [float(x) for x in parser.fIn.readline().split()] row2 = [float(x) for x in parser.fIn.readline().split()]
row2 = [float(x) for x in parser.fIn.readline().split()] row3 = [float(x) for x in parser.fIn.readline().split()]
row3 = [float(x) for x in parser.fIn.readline().split()] eigenvectors = np.array([row1, row2, row3])
eigenvectors = np.array([row1, row2, row3]) parser.backend.addArrayValues("x_cp2k_stress_tensor_eigenvalues", eigenvalues, unit="GPa")
parser.backend.addArrayValues("x_cp2k_stress_tensor_eigenvalues", eigenvalues, unit="GPa") parser.backend.addArrayValues("x_cp2k_stress_tensor_eigenvectors", eigenvectors)
parser.backend.addArrayValues("x_cp2k_stress_tensor_eigenvectors", eigenvectors)
return wrapper def adHoc_single_point_converged(self, parser):
def adHoc_single_point_converged(self):
"""Called when the SCF cycle of a single point calculation has converged. """Called when the SCF cycle of a single point calculation has converged.
""" """
def wrapper(parser): parser.backend.addValue("x_cp2k_quickstep_converged", True)
parser.backend.addValue("x_cp2k_quickstep_converged", True)
return wrapper
def adHoc_single_point_not_converged(self): def adHoc_single_point_not_converged(self, parser):
"""Called when the SCF cycle of a single point calculation did not converge. """Called when the SCF cycle of a single point calculation did not converge.
""" """
def wrapper(parser): parser.backend.addValue("x_cp2k_quickstep_converged", False)
parser.backend.addValue("x_cp2k_quickstep_converged", False)
return wrapper
def adHoc_x_cp2k_section_quickstep_atom_information(self): def adHoc_x_cp2k_section_quickstep_atom_information(self):
"""Used to extract the initial atomic coordinates and names in the """Used to extract the initial atomic coordinates and names in the
...@@ -680,17 +680,16 @@ class CP2KCommonParser(CommonParser): ...@@ -680,17 +680,16 @@ class CP2KCommonParser(CommonParser):
return wrapper return wrapper
def adHoc_dft_plus_u(self): def adHoc_dft_plus_u(self, parser):
def wrapper(parser): self.test_electronic_structure_method = "DFT+U"
self.test_electronic_structure_method = "DFT+U"
return wrapper
def adHoc_mp2(self): def adHoc_mp2(self, parser):
def wrapper(parser): self.test_electronic_structure_method = "MP2"
self.test_electronic_structure_method = "MP2"
return wrapper
def adHoc_rpa(self): def adHoc_rpa(self, parser):
def wrapper(parser): self.test_electronic_structure_method = "RPA"
self.test_electronic_structure_method = "RPA"
def adHoc_print(self, msg):
def wrapper(parser, groups):
print(msg)
return wrapper return wrapper
...@@ -70,20 +70,16 @@ class CP2KInputParser(AbstractBaseParser): ...@@ -70,20 +70,16 @@ class CP2KInputParser(AbstractBaseParser):
def parse(self, filepath): def parse(self, filepath):
#=======================================================================
# Preprocess to spell out variables and to include stuff from other # Preprocess to spell out variables and to include stuff from other
# files # files
self.preprocess_input(filepath) self.preprocess_input(filepath)
#=======================================================================
# Gather the information from the input file # Gather the information from the input file
self.fill_input_tree(filepath) self.fill_input_tree(filepath)
#=======================================================================
# Parse everything in the input to cp2k specific metadata # Parse everything in the input to cp2k specific metadata
self.fill_metadata() self.fill_metadata()
#=======================================================================
# Parse the used XC_functionals and their parameters # Parse the used XC_functionals and their parameters
xc = self.input_tree.get_section("FORCE_EVAL/DFT/XC/XC_FUNCTIONAL") xc = self.input_tree.get_section("FORCE_EVAL/DFT/XC/XC_FUNCTIONAL")
if xc is not None: if xc is not None:
......
...@@ -103,7 +103,7 @@ class CP2KMDParser(MainHierarchicalParser): ...@@ -103,7 +103,7 @@ class CP2KMDParser(MainHierarchicalParser):
subMatchers=[ subMatchers=[
self.cm.quickstep_calculation(), self.cm.quickstep_calculation(),
SM( " ENSEMBLE TYPE ="), SM( " ENSEMBLE TYPE ="),
SM( " STEP NUMBER ="), SM( " STEP NUMBER =\s+(?P<x_cp2k_md_step_number>{})".format(self.regexs.int)),
SM( " TIME \[fs\] =\s+(?P<x_cp2k_md_time__fs>{})".format(self.regexs.float)), SM( " TIME \[fs\] =\s+(?P<x_cp2k_md_time__fs>{})".format(self.regexs.float)),
SM( " CONSERVED QUANTITY \[hartree\] =\s+(?P<x_cp2k_md_conserved_quantity__hartree>{})".format(self.regexs.float)), SM( " CONSERVED QUANTITY \[hartree\] =\s+(?P<x_cp2k_md_conserved_quantity__hartree>{})".format(self.regexs.float)),
SM( " CPU TIME \[s\] =\s+(?P<x_cp2k_md_cpu_time_instantaneous>{})\s+(?P<x_cp2k_md_cpu_time_average>{})".format(self.regexs.float, self.regexs.float)), SM( " CPU TIME \[s\] =\s+(?P<x_cp2k_md_cpu_time_instantaneous>{})\s+(?P<x_cp2k_md_cpu_time_average>{})".format(self.regexs.float, self.regexs.float)),
...@@ -135,6 +135,7 @@ class CP2KMDParser(MainHierarchicalParser): ...@@ -135,6 +135,7 @@ class CP2KMDParser(MainHierarchicalParser):
forwardMatch=True, forwardMatch=True,
sections=["section_method"], sections=["section_method"],
subMatchers=[ subMatchers=[
self.cm.restart(),
self.cm.header(), self.cm.header(),
self.cm.quickstep_header(), self.cm.quickstep_header(),
], ],
...@@ -260,7 +261,7 @@ class CP2KMDParser(MainHierarchicalParser): ...@@ -260,7 +261,7 @@ class CP2KMDParser(MainHierarchicalParser):
if add_last_vel_setting == "NUMERIC" or add_last_vel_setting == "SYMBOLIC": if add_last_vel_setting == "NUMERIC" or add_last_vel_setting == "SYMBOLIC":
add_last_vel = True add_last_vel = True
last_step = self.n_steps - 1 last_step = self.n_steps
md_steps = section["x_cp2k_section_md_step"] md_steps = section["x_cp2k_section_md_step"]
frame_sequence_potential_energy = [] frame_sequence_potential_energy = []
...@@ -269,10 +270,24 @@ class CP2KMDParser(MainHierarchicalParser): ...@@ -269,10 +270,24 @@ class CP2KMDParser(MainHierarchicalParser):
frame_sequence_kinetic_energy = [] frame_sequence_kinetic_energy = []
frame_sequence_conserved_quantity = [] frame_sequence_conserved_quantity = []
frame_sequence_pressure = [] frame_sequence_pressure = []
ener_frames = []
single_conf_gids = [] single_conf_gids = []
i_md_step = 0 i_md_step = 0
# Check that is the calculation starting from first frame. If not, this
# is a restarted calculation. In this case it is practically impossible
# to know from which frame number we should start reading the
# configurations, because the print settings in the previous runs may
# have been different from now, and the step numbers are hard to align.
# In this case we just parse what is found in this output file
start_step_number = md_steps[1]["x_cp2k_md_step_number"][0]
if start_step_number != 1:
self.traj_iterator = None
self.cell_iterator = None
self.vel_iterator = None
self.energy_iterator = None
for i_step in range(self.n_steps + 1): for i_step in range(self.n_steps + 1):
sectionGID = backend.openSection("section_single_configuration_calculation") sectionGID = backend.openSection("section_single_configuration_calculation")
...@@ -290,7 +305,7 @@ class CP2KMDParser(MainHierarchicalParser): ...@@ -290,7 +305,7 @@ class CP2KMDParser(MainHierarchicalParser):
# Trajectory # Trajectory
if freqs["trajectory"][1] and self.traj_iterator is not None: if freqs["trajectory"][1] and self.traj_iterator is not None:
if (i_step + 1) % freqs["trajectory"][0] == 0 or (i_step == last_step and add_last_traj): if (i_step) % freqs["trajectory"][0] == 0 or (i_step == last_step and add_last_traj):
try: try:
pos = next(self.traj_iterator) pos = next(self.traj_iterator)
except StopIteration: except StopIteration:
...@@ -300,7 +315,7 @@ class CP2KMDParser(MainHierarchicalParser): ...@@ -300,7 +315,7 @@ class CP2KMDParser(MainHierarchicalParser):
# Velocities # Velocities
if freqs["velocities"][1] and self.vel_iterator is not None: if freqs["velocities"][1] and self.vel_iterator is not None:
if (i_step + 1) % freqs["velocities"][0] == 0 or (i_step == last_step and add_last_vel): if (i_step) % freqs["velocities"][0] == 0 or (i_step == last_step and add_last_vel):
try: try:
vel = next(self.vel_iterator) vel = next(self.vel_iterator)
except StopIteration: except StopIteration:
...@@ -310,7 +325,7 @@ class CP2KMDParser(MainHierarchicalParser): ...@@ -310,7 +325,7 @@ class CP2KMDParser(MainHierarchicalParser):
# Energy file # Energy file
if self.energy_iterator is not None: if self.energy_iterator is not None:
if (i_step + 1) % freqs["energies"][0] == 0: if (i_step) % freqs["energies"][0] == 0:
line = next(self.energy_iterator) line = next(self.energy_iterator)
time = line[1] time = line[1]
...@@ -326,20 +341,30 @@ class CP2KMDParser(MainHierarchicalParser): ...@@ -326,20 +341,30 @@ class CP2KMDParser(MainHierarchicalParser):
frame_sequence_potential_energy.append(potential_energy) frame_sequence_potential_energy.append(potential_energy)
frame_sequence_conserved_quantity.append(conserved_quantity) frame_sequence_conserved_quantity.append(conserved_quantity)
ener_frames.append(i_step)
backend.addValue("energy_total", conserved_quantity) backend.addValue("energy_total", conserved_quantity)
backend.addValue("time_calculation", wall_time) backend.addValue("time_calculation", wall_time)
# Cell file # Cell file
if self.cell_iterator is not None: if self.cell_iterator is not None:
if (i_step + 1) % freqs["cell"][0] == 0: if (i_step) % freqs["cell"][0] == 0:
line = next(self.cell_iterator) line = next(self.cell_iterator)
cell = np.reshape(line, (3, 3)) cell = np.reshape(line, (3, 3))
self.backend.addArrayValues("simulation_cell", cell, unit="angstrom") self.backend.addArrayValues("simulation_cell", cell, unit="angstrom")
# Output file # Output file
if md_steps: if md_steps:
if (i_step + 1) % freqs["output"][0] == 0: if (i_step) % freqs["output"][0] == 0:
md_step = md_steps[i_md_step] try:
md_step = md_steps[i_md_step]