From 9efa31c40e7321198d0777a1bb117b2d68794995 Mon Sep 17 00:00:00 2001
From: mkirsz <s1351949@sms.ed.ac.uk>
Date: Wed, 26 Feb 2025 09:04:48 +0000
Subject: [PATCH] Parser improvements

---
 src/castep_castep_reader.cpp | 594 +++++++++++------------------------
 1 file changed, 187 insertions(+), 407 deletions(-)

diff --git a/src/castep_castep_reader.cpp b/src/castep_castep_reader.cpp
index b04545e..bc9a055 100644
--- a/src/castep_castep_reader.cpp
+++ b/src/castep_castep_reader.cpp
@@ -36,6 +36,73 @@ void CastepCastepReader::parse_data() {
     SinglePoint         // SCF or single-point run
   };
 
+  struct Label {
+    Label(const std::string& filename) : filename(filename) {}
+    CalcState calcState = CalcState::Idle;
+    std::string simType = "Unknown";
+    std::string algo = "Unknown";
+    std::string ensemble = "Unknown";
+    int startLine = -1;
+    int stopLine = -1;
+    int positionsStartLine = -1;
+    int positionsStopLine = -1;
+    int forcesStartLine = -1;
+    int forcesStopLine = -1;
+    int stressStartLine = -1;
+    int stressStopLine = -1;
+    int energyLine = -1;
+    double T=-1.0;
+    std::string stress="DNF";
+    bool useStress=false;
+    std::size_t stepNumber=0;
+    std::string filename;
+
+    std::string getStateLabel() {
+      switch (calcState) {
+        case CalcState::Idle: return "Idle";
+        case CalcState::GeometryOptimization: return "GO";
+        case CalcState::MolecularDynamics: return "MD";
+        case CalcState::SinglePoint: return "SPC";
+      }
+      return "Unknown";
+    }
+    std::string getMDLabel() {
+      std::string state = getStateLabel();
+      return "File: " + filename + " Lines: (" + std::to_string(startLine) + " : " + std::to_string(stopLine) + ") "
+      + simType + " " + ensemble + " T: " + std::to_string(T) + " Step: " + std::to_string(stepNumber) + " Stress: " + stress
+      + " Parser State: " + state
+      + " | C: (" + std::to_string(positionsStartLine) + " : " + std::to_string(positionsStopLine)
+      + ") F: (" + std::to_string(forcesStartLine) + " : " + std::to_string(forcesStopLine)
+      + ") S: (" + std::to_string(stressStartLine) + " : " + std::to_string(stressStopLine) + ") + E: " + std::to_string(energyLine);
+    }
+    std::string getGOLabel() {
+      std::string state = getStateLabel();
+      return "File: " + filename + " Lines: (" + std::to_string(startLine) + " : " + std::to_string(stopLine) + ") " 
+      + simType + " " + algo + " Step: " + std::to_string(stepNumber) + " stress: " + stress + " Parser State: " + state
+      + " | C: (" + std::to_string(positionsStartLine) + " : " + std::to_string(positionsStopLine)
+      + ") F: (" + std::to_string(forcesStartLine) + " : " + std::to_string(forcesStopLine)
+      + ") S: (" + std::to_string(stressStartLine) + " : " + std::to_string(stressStopLine) + ") + E: " + std::to_string(energyLine);
+    }
+    std::string getSPLabel() {
+      std::string state = getStateLabel();
+      return "File: " + filename + " Lines: (" + std::to_string(startLine) + " : " + std::to_string(stopLine) + ") " 
+      + simType + " SPC #: " + std::to_string(stepNumber) + " stress: " + stress + " Parser State: " + state
+      + " | C: (" + std::to_string(positionsStartLine) + " : " + std::to_string(positionsStopLine)
+      + ") F: (" + std::to_string(forcesStartLine) + " : " + std::to_string(forcesStopLine)
+      + ") S: (" + std::to_string(stressStartLine) + " : " + std::to_string(stressStopLine) + ") + E: " + std::to_string(energyLine);
+    }
+    std::string getLabel() {
+      switch (calcState) {
+        case CalcState::Idle: return "Idle";
+        case CalcState::GeometryOptimization: return getGOLabel();
+        case CalcState::MolecularDynamics: return getMDLabel();
+        case CalcState::SinglePoint: return getSPLabel();
+      }
+      return "Unknown";
+    }
+
+  } simLabel(filename);
+
   // Current parser state and relevant flags
   CalcState current_state = CalcState::Idle; 
   bool stress_tensor_found = false;
@@ -44,7 +111,6 @@ void CastepCastepReader::parse_data() {
 
   // Local counters and accumulators
   size_t natoms = 0;                // Number of atoms from the input
-  int scf_counter = 0;              // Index for SCF runs (tracking distinct single-point steps)
   size_t line_counter = 0;          // Tracks line number for warnings
   bool debug = false;               // Local debug toggle
 
@@ -52,6 +118,17 @@ void CastepCastepReader::parse_data() {
   Structure s;              
   std::vector<Atom> atoms;
 
+  std::string line;
+  auto jumpNLines = [&](std::istringstream& stream, int n) {
+    for (int i = 0; i < n; ++i) {
+      if (!std::getline(stream, line)) {
+        std::cerr << "Warning: Unexpected end of file while skipping lines" << std::endl;
+        break;
+      }
+      ++line_counter;
+    }
+  };
+
   // Internal helper to finalize a structure's data:
   // This updates derived data (like stress if absent) and adds to the structure DB.
   auto finalize_structure = [&]() {
@@ -69,6 +146,7 @@ void CastepCastepReader::parse_data() {
       s.atoms[i].force = atoms[i].force;
       s.atoms[i].symbol = atoms[i].symbol;
     }
+    s.label = simLabel.getLabel();
     stdb.add(s);
   };
 
@@ -81,21 +159,86 @@ void CastepCastepReader::parse_data() {
 
   // Use a string stream to iterate over lines in raw_data_ 
   std::istringstream stream(raw_data_);
-  std::string line;
   while (std::getline(stream, line)) {
     ++line_counter;
 
+    // Detect starting SP calculation (zeroth step)
+    if (line.find("single point energy") != std::string::npos) {
+      reset_flags(CalcState::SinglePoint);
+      if (!std::getline(stream, line)) break; 
+      ++line_counter;
+      std::istringstream iss(line);
+      std::string ignore, stress;
+      iss >> ignore >> ignore >> ignore >> stress;
+      simLabel.calcState = CalcState::SinglePoint;
+      simLabel.startLine = line_counter;
+      simLabel.simType = "CASTEP SPC";
+      simLabel.stepNumber = 0;
+      simLabel.stress = stress;
+      simLabel.useStress = stress == "on" ? true : false;
+      if (debug) std::cout << "single point energy" << std::endl;
+    }
+
+    // Detect starting GO calculation (zeroth step)
+    if (line.find("geometry optimization") != std::string::npos) {
+      reset_flags(CalcState::GeometryOptimization);
+      jumpNLines(stream, 1);
+      std::istringstream iss(line);
+      std::string ignore, stress;
+      iss >> ignore >> ignore >> ignore >> stress;
+      simLabel.calcState = CalcState::GeometryOptimization;
+      simLabel.startLine = line_counter;
+      simLabel.simType = "CASTEP GO";
+      simLabel.stepNumber = 0;
+      simLabel.stress = stress;
+      simLabel.useStress = stress == "on" ? true : false;
+      if (debug) std::cout << "geometry optimization" << std::endl;
+    }
+
+    // Detect MD calculation type (zeroth step)
+    if (line.find("molecular dynamics") != std::string::npos) {
+      reset_flags(CalcState::MolecularDynamics);
+      jumpNLines(stream, 1);
+      std::istringstream iss(line);
+      std::string ignore, stress;
+      iss >> ignore >> ignore >> ignore >> stress;
+      simLabel.calcState = CalcState::MolecularDynamics;
+      simLabel.startLine = line_counter;
+      simLabel.simType = "CASTEP MD";
+      simLabel.stepNumber = 0;
+      simLabel.stress = stress;
+      simLabel.useStress = stress == "on" ? true : false;
+      if (debug) std::cout << "molecular dynamics" << std::endl;
+    }
+
+    // Get GO algorithm name at step zero
+    if (line.find("Geometry Optimization Parameters") != std::string::npos) {
+      std::string ignore, algo;
+      jumpNLines(stream, 2);
+      std::istringstream iss(line);
+      iss >> ignore >> ignore >> ignore >> algo;
+      simLabel.algo = algo;
+      if (debug) std::cout << "Geometry Optimization Parameters" << std::endl;
+    }
+
+    // Get MD ensemble name at step zero
+    if (line.find("Molecular Dynamics Parameters") != std::string::npos) {
+      reset_flags(CalcState::MolecularDynamics);
+      jumpNLines(stream, 2);
+      std::istringstream iss(line);
+      std::string ignore, ensemble;
+      iss >> ignore >> ignore >> ensemble;
+      simLabel.ensemble = ensemble;
+      if (debug) std::cout << "Molecular Dynamics Parameters" << std::endl;
+    }
+
     // Detect or store the "Unit Cell"
     if (line.find("Unit Cell") != std::string::npos) {
       // A new cell is encountered. Prepare to read the next three lines of vectors.
       // Finalize any incomplete data set if logic demands it, but not strictly necessary here
       if (debug) std::cout << "Reading 3 lines of Unit Cell" << std::endl;
       
-      // Skip the next two lines, often blank or headers
-      if (!std::getline(stream, line)) break; 
-      ++line_counter;
-      if (!std::getline(stream, line)) break; 
-      ++line_counter;
+      jumpNLines(stream, 2);
 
       // Read the 3 lattice vectors
       for (int i = 0; i < 3; ++i) {
@@ -134,109 +277,45 @@ void CastepCastepReader::parse_data() {
       continue;
     }
 
-    // Detect starting MD iteration
-    if (line.find("Starting MD iteration") != std::string::npos) {
-      reset_flags(CalcState::MolecularDynamics);
-      std::istringstream iss(line);
-      std::string ignore, step;
-      iss >> ignore >> ignore >> ignore >> step;
-
-      // Remove last step from label
-      while (s.label.back() != ' ') 
-        s.label.pop_back();
-
-      s.label += step;
-
-      if (debug) std::cout << "Starting MD iteration " << step << std::endl;
-      continue;
-    }
-
-    // Detect starting SP calculation (zeroth step)
-    if (line.find("single point energy") != std::string::npos) {
-      reset_flags(CalcState::SinglePoint);
-      if (!std::getline(stream, line)) break; 
-      ++line_counter;
-      std::istringstream iss(line);
-      std::string ignore, stress;
-      iss >> ignore >> ignore >> ignore >> stress;
-      s.label = "File: " + filename + " | CASTEP single point calculation, stress: " + stress;
-      if (stress == "on") {
-        is_stress = true;
-      }
-      else {
-        is_stress = false;
-      }
-      if (debug) std::cout << "single point energy" << std::endl;
-    }
-
-    // Detect starting GO iteration (zeroth step)
-    if (line.find("Geometry Optimization Parameters") != std::string::npos) {
-      reset_flags(CalcState::GeometryOptimization);
-      std::string ignore, algo;
-
-      if (!std::getline(stream, line)) break; 
-      ++line_counter;
-      if (!std::getline(stream, line)) break; 
-      ++line_counter;
-      std::istringstream iss(line);
-      iss >> ignore >> ignore >> ignore >> algo;
-      s.label = "File: " + filename + " | CASTEP GO, "+algo+ ", step: ";
-      if (debug) std::cout << "Geometry Optimization Parameters" << std::endl;
-    }
-
-    // Detect starting MD simulation (zeroth step)
-    if (line.find("Molecular Dynamics Parameters") != std::string::npos) {
-      reset_flags(CalcState::MolecularDynamics);
-
-      if (!std::getline(stream, line)) break; 
-      ++line_counter;
-      if (!std::getline(stream, line)) break; 
-      ++line_counter;
-      std::istringstream iss(line);
-      std::string ignore, ensemble;
-      iss >> ignore >> ignore >> ensemble;
-      s.label = "File: " + filename + " | CASTEP MD, "+ensemble+" step: " + "0";
-      if (debug) std::cout << "Molecular Dynamics Parameters" << std::endl;
-      continue;
-    }
-
-    // Detect starting GO iteration
+    // Detect GO iteration
     if (line.find("Starting BFGS iteration") != std::string::npos || 
         line.find("Starting LBFGS iteration") != std::string::npos || 
         line.find("Starting Delocalized iteration") != std::string::npos || 
         line.find("Starting DampedMD iteration") != std::string::npos || 
         line.find("Starting TPSD iteration") != std::string::npos) {
       reset_flags(CalcState::GeometryOptimization);
-      // This line often carries the iteration number
       std::istringstream iss(line);
       std::string ignore, algo, step_str;
-      // The typical format: "Starting MD iteration N ..."
-      // Attempt to parse out the iteration number as step_str
       iss >> ignore >> algo >> ignore >> step_str;
-      // Store it in a label for clarity
-      s.label = "File: " + filename + " | CASTEP GO, "+algo+" step: ";
+      simLabel.simType = "CASTEP GO";
+      simLabel.startLine = line_counter;
+      simLabel.algo = algo;
+      simLabel.stepNumber = std::stoi(step_str);
+      simLabel.calcState = CalcState::GeometryOptimization;
       if (debug) std::cout << "Starting" +algo+ " iteration " << step_str << std::endl;
-      continue;
     }
 
-    // if (line.find("finished MD iteration") != std::string::npos) {
-    //   reset_flags(CalcState::Idle);
-    // }
+    // Detect MD iteration
+    if (line.find("Starting MD iteration") != std::string::npos) {
+      reset_flags(CalcState::MolecularDynamics);
+      std::istringstream iss(line);
+      std::string ignore, step;
+      iss >> ignore >> ignore >> ignore >> step;
+      simLabel.simType = "CASTEP MD";
+      simLabel.startLine = line_counter;
+      simLabel.stepNumber = std::stoi(step);
+      simLabel.calcState = CalcState::MolecularDynamics;
+      if (debug) std::cout << "Starting MD iteration " << step << std::endl;
+      continue;
+    }
 
     // Detect fractional coordinates block
     if (line.find("Fractional coordinates of atoms") != std::string::npos) {
       if (debug) std::cout << "Fractional coordinates of atoms" << std::endl;
-      // Typically followed by two header/blank lines
-      if (!std::getline(stream, line)) break; 
-      ++line_counter;
-      if (!std::getline(stream, line)) break; 
-      ++line_counter;
-
-      // If constant volume, the code does not always reprint the cell.  
-      // The logic here re-uses the last known cell if needed. 
+      jumpNLines(stream, 2);
       atoms.clear(); // Clear old atoms or partial data
-
       atoms.reserve(natoms);
+      simLabel.positionsStartLine = line_counter + 1;
       for (size_t i = 0; i < natoms; ++i) {
         if (!std::getline(stream, line)) {
           std::cerr << "Warning: Truncated file reading fractional coords at row " << i 
@@ -258,7 +337,7 @@ void CastepCastepReader::parse_data() {
         Atom a(Element(species), px, py, pz, 0.0, 0.0, 0.0);
         atoms.push_back(a); // keep it fractional for now
       }
-      continue;
+      simLabel.positionsStopLine = line_counter;
     }
 
     // The old cell is reverted and printed before final enthalpy from the current iteration
@@ -278,14 +357,9 @@ void CastepCastepReader::parse_data() {
     if (line.find("Cartesian components (eV/A)") != std::string::npos) {
       if (debug) std::cout << "Reading forces..." << std::endl;
       // Usually there are three lines of header/blank text before actual force lines
-      for (int i = 0; i < 3; ++i) {
-        if (!std::getline(stream, line)) {
-          std::cerr << "Warning: Incomplete forces header block (line: " << line_counter << ")." << std::endl;
-          break;
-        }
-        ++line_counter;
-      }
+      jumpNLines(stream, 3);
       // Read force for each atom
+      simLabel.forcesStartLine = line_counter+1;
       for (size_t i = 0; i < natoms; ++i) {
         if (!std::getline(stream, line)) {
           std::cerr << "Warning: Truncated file reading forces at row " << i
@@ -297,32 +371,24 @@ void CastepCastepReader::parse_data() {
         std::istringstream iss(line);
         std::string tmp;
         double fx, fy, fz;
-        // Format typically: " ??? ??? ??? fx fy fz "
         if (!(iss >> tmp >> tmp >> tmp >> fx >> fy >> fz)) {
           std::cerr << "Warning: Could not parse atomic forces (line: " 
                     << line_counter << ")." << std::endl;
           break;
         }
-        // Assign force to the matching atom
         if (i < atoms.size()) {
           atoms[i].force = Vec3d(fx, fy, fz);
         }
       }
-      continue;
+      simLabel.forcesStopLine = line_counter;
     }
 
     // Detect stress block
     if (line.find("Cartesian components (GPa)") != std::string::npos) {
       if (debug) std::cout << "Reading stress..." << std::endl;
-      // Usually there are three lines of header/blank text
-      for (int i = 0; i < 3; ++i) {
-        if (!std::getline(stream, line)) {
-          std::cerr << "Warning: Incomplete stress header block (line: " << line_counter << ")." << std::endl;
-          break;
-        }
-        ++line_counter;
-      }
+      jumpNLines(stream, 3);
       // A 3x3 matrix is expected
+      simLabel.stressStartLine = line_counter + 1;
       for (int row = 0; row < 3; ++row) {
         if (!std::getline(stream, line)) {
           std::cerr << "Warning: Truncated file reading stress row " << row 
@@ -333,7 +399,6 @@ void CastepCastepReader::parse_data() {
         std::istringstream iss(line);
         std::string ignore;
         double v1, v2, v3;
-        // Format: " ??? ??? val1 val2 val3 "
         if (!(iss >> ignore >> ignore >> v1 >> v2 >> v3)) {
           std::cerr << "Warning: Could not parse stress row (line: " 
                     << line_counter << ")." << std::endl;
@@ -342,13 +407,14 @@ void CastepCastepReader::parse_data() {
         s.stress(row, 0) = v1;
         s.stress(row, 1) = v2;
         s.stress(row, 2) = v3;
+        simLabel.stressStopLine = line_counter;
       }
       stress_tensor_found = true;
       if (current_state == CalcState::SinglePoint) {
-        s.label += " SCF run: " + std::to_string(scf_counter++);
+        simLabel.stepNumber++; 
         if (is_stress) data_block_complete = true;
+        simLabel.stopLine = line_counter;
       }
-      continue;
     }
 
     // Detect final free energy for single-point or last iteration in GO
@@ -366,16 +432,16 @@ void CastepCastepReader::parse_data() {
                   << line_counter << ")." << std::endl;
       } else {
         s.energy = energy;
+        simLabel.energyLine = line_counter;
       }
 
       // Single-point detection: if current_state is Idle or SinglePoint, treat it as an SCF run
       // but it might also appear mid-GO. The code below sets a label if no other structure data is present.
       if (current_state == CalcState::SinglePoint && !is_stress) {
-        s.label += " SCF run: " + std::to_string(scf_counter++);
+        simLabel.stepNumber++; 
+        simLabel.stopLine = line_counter;
         data_block_complete = true;
       }
-      // Mark that data is complete for this structure
-      continue;
     }
 
     // Detect the line with "enthalpy=" used in geometry optimization
@@ -388,15 +454,14 @@ void CastepCastepReader::parse_data() {
         std::cerr << "Warning: Could not parse final free energy (line: "
                   << line_counter << ")." << std::endl;
       }
-      s.label += step;
+      simLabel.stepNumber = std::stoi(step);
+      simLabel.stopLine = line_counter;
       data_block_complete = true;
-      continue;
     }
 
     // Detect potential energy line used in MD 
     if (line.find("Potential Energy:") != std::string::npos && current_state == CalcState::MolecularDynamics) {
       if (debug) std::cout << "Potential Energy:" << std::endl;
-      // Format: "Potential Energy: <value>"
       std::istringstream iss(line);
       std::string ignore;
       double energy;
@@ -416,19 +481,15 @@ void CastepCastepReader::parse_data() {
       std::istringstream iss(line);
       std::string ignore;
       double temperature;
-      // Format: "Temperature: <value>"
       if (!(iss >> ignore >> ignore >> temperature)) {
         std::cerr << "Warning: Could not parse temperature in MD (line: " 
                   << line_counter << ")." << std::endl;
       } else {
         s.T = temperature;
       }
-      // If a label has not been set, create a fallback
-      // if (s.label.empty()) {
-      //   s.label = "CASTEP MD step (no step # found)";
-      // }
+      simLabel.T = temperature;
+      simLabel.stopLine = line_counter;
       data_block_complete = true;
-      continue;
     }
 
     // If a completed data set is detected, finalize
@@ -437,289 +498,8 @@ void CastepCastepReader::parse_data() {
       reset_flags(CalcState::Idle);
     }
   } // end while getline
-
-  // At file end, if a data block was incomplete but has partial data, 
-  // it can either be discarded or stored as partial. 
-  // For safety, only store if data_block_complete was triggered.
-  // No action is taken here unless a user-specific policy is desired.
 }
 
-// void CastepCastepReader::parse_data() {
-//   std::istringstream stream(raw_data_);
-//   std::string line;
-//
-//   size_t natoms;;
-//   bool stress_tensor_bool = false;
-//   bool constant_volume = false;
-//   bool complete_structure = false;
-//   bool md_run = false;
-//   bool go_run = false;
-//   bool restart = false;
-//   int scf_idx = 0;
-//
-//   Structure s;
-//   std::string label;
-//   size_t counter=0;
-//
-//   bool debug = false;
-//
-//   while (std::getline(stream, line)) {
-//
-//     if (line.find("type of calculation") != std::string::npos) {
-//       stress_tensor_bool=false;
-//       constant_volume=false;
-//       md_run = false;
-//       go_run = false;
-//       restart=false;
-//       if (line.find(": geometry optimization") != std::string::npos) {
-//         if (debug) std::cout << "GO run" << std::endl;
-//         go_run = true;
-//       }
-//       if (line.find(": molecular dynamics") != std::string::npos) {
-//         md_run = true;
-//       }
-//     }
-//     else if (line.find("Restarting MD") != std::string::npos) {
-//       restart=true;
-//     }
-//     else if (line.find("Unit Cell") != std::string::npos) {
-//       if (debug) std::cout << "Unit Cell" << std::endl;
-//       if (!std::getline(stream, line) || !std::getline(stream, line)) {
-//         std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//         std::cerr << "Warning: Unexpected end of data when reading atom information" << std::endl;
-//       }
-//       counter++;
-//       counter++;
-//
-//       s = Structure();
-//       for (int i = 0; i < 3; ++i) {
-//         if (!std::getline(stream, line)) {
-//           std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//           std::cerr << "Warning: Unexpected end of data when reading lattice vectors at row " << i << std::endl;
-//           break;
-//         }
-//         counter++;
-//         std::istringstream iss(line);
-//         if (!(iss >> s.cell(0,i) >> s.cell(1,i) >> s.cell(2,i))) {
-//           std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//           std::cerr << "Warning: Unexpected end of data when reading lattice vectors at row " << i << std::endl;
-//           break;
-//         }
-//       }
-//
-//       if (constant_volume) label.clear();
-//       constant_volume = false;
-//       if (debug) std::cout << s.cell << std::endl;
-//     }
-//
-//     else if (line.find("Total number of ions in cell") != std::string::npos) {
-//       // this line indicates new type of computation, so we reset flags here
-//       std::istringstream iss(line);
-//       std::string temp;
-//       int count = 0;
-//
-//       // Process the line to reach the 8th element
-//       while (iss >> temp) {
-//         if (++count == 7 && !(iss >> natoms)) {
-//           std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//           std::cerr << "Error: Failed to read number of atoms from line: " << line << std::endl;
-//         }
-//       }
-//
-//       // Check if the line was too short
-//       if (count < 7) {
-//         std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//         std::cerr << "Error: Line is too short to extract total number of ions in a cell. Line: " << line << std::endl;
-//       }
-//       if (debug) std::cout << "Number of atoms: " << natoms << std::endl;
-//     }
-//
-//     else if (line.find("so fixing cell parameters") != std::string::npos) {
-//       if (debug) std::cout << "so fixing cell parameters" << std::endl;
-//       constant_volume=true;
-//       label = "CASTEP MD, const. volume: true, step: 0";
-//     }
-//
-//     else if (line.find("Starting MD iteration") != std::string::npos) {
-//       if (debug) std::cout << "Starting MD iteration" << std::endl;
-//       std::istringstream iss(line);
-//       std::string step;
-//       iss >> step >> step >> step >> step;
-//       std::ostringstream oss;
-//       oss << std::boolalpha << constant_volume;
-//       label = "CASTEP MD, const. volume: " + oss.str() + ", step: " + step;
-//     }
-//
-//
-//     else if (constant_volume && line.find("Cell Contents") != std::string::npos) {
-//       if (debug) std::cout << "Cell Contents" << std::endl;
-//       if (restart) {
-//         if (debug) std::cout << "Cell Contents restart" << std::endl;
-//         s.atoms.clear();
-//       } else {
-//         if (debug) std::cout << "Cell Contents no restart" << std::endl;
-//         if (debug) std::cout << line << std::endl;
-//         s = Structure();
-//         s.cell = stdb.structures.back().cell;   // copy last cell as it is not repeated in castep for const. volume
-//       }
-//     }
-//
-//     else if (line.find("Fractional coordinates of atoms") != std::string::npos) {
-//       if (debug) std::cout << "Fractional coordinates of atoms" << std::endl;
-//       // Ideally st.natoms() should be zero by now. However for constant volum GO this is not the case.
-//       // Therfore we need to clear the atoms vector but we keep the st.cell as it is.
-//       s.atoms.clear();
-//       if (!std::getline(stream, line) || !std::getline(stream, line)) {
-//         std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//         std::cerr << "Warning: Unexpected end of data when reading atom information" << std::endl;
-//       }
-//       counter++;
-//       counter++;
-//
-//       for (size_t i = 0; i < natoms; ++i) {
-//         if (!std::getline(stream, line)) {
-//           std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//           std::cerr << "Warning: Unexpected end of data when reading atomic coordinates at row " << i << std::endl;
-//           break;
-//         }
-//         counter++;
-//         std::istringstream iss(line);
-//         std::string type, tmp;
-//         double px,py,pz;
-//         if (!(iss >> tmp >> type >> tmp >> px >> py >> pz)) {
-//           std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//           std::cerr << "Warning: Unexpected end of data when reading atomic coordiantes at row " << i << std::endl;
-//           break;
-//         }
-//         s.add_atom(Atom(Element(type),px,py,pz,0,0,0));
-//         s.atoms[i].position = s.cell * s.atoms[i].position;  // convert to abs
-//       }
-//       if (debug) std::cout << "natoms: " << s.natoms() << std::endl;
-//     }
-//
-//     else if (line.find("Cartesian components (eV/A)") != std::string::npos) {
-//       if (debug) std::cout << "Cartesian components (eV/A)" << std::endl;
-//       if (s.natoms()!=natoms) continue;
-//       if (!std::getline(stream, line) || !std::getline(stream, line) || !std::getline(stream, line)) {
-//         std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//         std::cerr << "Warning: Unexpected end of data when reading atom forces" << std::endl;
-//       }
-//       counter++;
-//       counter++;
-//       counter++;
-//       for (size_t i = 0; i < natoms; ++i) {
-//         if (!std::getline(stream, line)) {
-//           std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//           std::cerr << "Warning: Unexpected end of data when reading atom forces: " << line << std::endl;
-//           break;
-//         }
-//         counter++;
-//         std::istringstream iss(line);
-//         std::string tmp;
-//         double fx,fy,fz;
-//         if (!(iss >> tmp >> tmp >> tmp >> fx >> fy >> fz)) {
-//           std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//           std::cerr << "Warning: Unexpected end of data when reading atom forces: " << line << std::endl;
-//         } else {
-//           s.atoms[i].force = Vec3d(fx,fy,fz);
-//         }
-//       }
-//     }
-//
-//     else if (line.find("Cartesian components (GPa)") != std::string::npos) {
-//       if (debug) std::cout << "Cartesian components (GPa)" << std::endl;
-//       if (!std::getline(stream, line) || !std::getline(stream, line) || !std::getline(stream, line)) {
-//         std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//         std::cerr << "Warning: Unexpected end of data when reading stress tensor" << std::endl;
-//       }
-//       counter++;
-//       counter++;
-//       counter++;
-//       for (size_t i = 0; i < 3; ++i) {
-//         if (!std::getline(stream, line)) {
-//           std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//           std::cerr << "Warning: Unexpected end of data when reading stress tensor: " << line << std::endl;
-//           break;
-//         }
-//         counter++;
-//         std::istringstream iss(line);
-//         std::string tmp;
-//         if (!(iss >> tmp >> tmp >> s.stress(i,0) >> s.stress(i,1) >> s.stress(i,2))) {
-//           std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//           std::cerr << "Warning: Unexpected end of data when reading atom forces: " << line << std::endl;
-//         } 
-//       }
-//       stress_tensor_bool = true;
-//     }
-//     // Potential Energy // MD
-//     // Total energy corrected for finite basis set =   -2690.182502 eV  // GO, first step only
-//     // enthalpy=  indicates end of iteration for GO
-//
-//     else if (line.find("Final free energy (E-TS)") != std::string::npos) {
-//       if (debug) std::cout << "Final free energy (E-TS)" << std::endl;
-//       std::istringstream iss(line);
-//       std::string tmp;
-//       if (!(iss >> tmp >> tmp >> tmp >> tmp >> tmp >> s.energy)) {
-//         std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//         std::cerr << "Warning: Unexpected end of data when reading total energy" << std::endl;
-//       }
-//       // scf only loop
-//       if (!md_run && !go_run) {
-//         s.label = "SCF run: " + std::to_string(scf_idx++);
-//         complete_structure = true;
-//       }
-//     }
-//
-//     else if (line.find("enthalpy=") != std::string::npos) {
-//       if (debug) std::cout << "enthalpy=" << std::endl;
-//       // GO: the last extracted free energy is correct one!
-//       std::istringstream iss(line);
-//       std::string step;
-//       iss >> step >> step >> step >> step;  // safe as found enthalpy=
-//       std::ostringstream oss;
-//       oss << std::boolalpha << constant_volume;
-//       s.label = "CASTEP GO, const. volume: " + oss.str() + ", step: " + step;
-//       complete_structure = true;
-//     }
-//
-//     else if (line.find("Potential Energy:") != std::string::npos) {
-//       if (debug) std::cout << "Potential Energy:" << std::endl;
-//       std::istringstream iss(line);
-//       std::string tmp;
-//       if (!(iss >> tmp >> tmp >> tmp >> s.energy)) {
-//         std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//         std::cerr << "Warning: Unexpected end of data when reading total energy" << std::endl;
-//       }
-//     }
-//     else if (line.find("Temperature:") != std::string::npos) {
-//       if (debug) std::cout << "Temperature:" << std::endl;
-//       // MD: end of iteration
-//       std::istringstream iss(line);
-//       std::string tmp;
-//       if (!(iss >> tmp >> tmp >> s.T)) {
-//         std::cerr << "Warning, file" << filename << " line: " << counter << std::endl;
-//         std::cerr << "Warning: Unexpected end of data when reading temperature" << std::endl;
-//       }
-//
-//       if (!label.size())label = "CASTEP MD, const. volume: false, step: 0"; // the last option
-//       s.label = label;
-//       complete_structure = true;
-//     }
-//     if (complete_structure) {
-//       if (!stress_tensor_bool) {
-//         s.stress.set_zero();
-//       }
-//       else  {
-//         s.stress *= p_conv; // GPa -> eV/A^3
-//       }
-//       stdb.add(s);
-//       complete_structure = false;
-//     }
-//     counter++;
-//   }
-//
-// }
-
 void CastepCastepReader::print_summary() const {
   std::cout << get_summary();
 }
-- 
GitLab