process_log.m 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #!/usr/bin/env octave
  2. % Copyright (C) 2019 Kei Kebreau
  3. %
  4. % This program is free software: you can redistribute it and/or modify
  5. % it under the terms of the GNU General Public License as published by
  6. % the Free Software Foundation, either version 3 of the License, or
  7. % (at your option) any later version.
  8. %
  9. % This program is distributed in the hope that it will be useful,
  10. % but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. % GNU General Public License for more details.
  13. %
  14. % You should have received a copy of the GNU General Public License
  15. % along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. % Let user select input file.
  17. [input_file, file_path] = uigetfile({'*.log*', 'Supported file formats'});
  18. % Load the input file.
  19. raw_data = fileread([file_path input_file]);
  20. [~, file_name, ~] = fileparts(input_file);
  21. % Let user select output directory.
  22. output_dir = uigetdir('.', 'Select output directory for graph and xyz files');
  23. % Get the number of atoms.
  24. num_atoms = regexp(raw_data, 'NAtoms=\s+(\d+)', 'tokens', 'once');
  25. % Extract the string from the cell array and convert it to a number.
  26. num_atoms = str2num(num_atoms{1});
  27. % There *has* to be a better way to do this, but for now it works... :-/
  28. intermediate_cluster_regexp = ['Standard orientation:' repmat('\D+\d+\s+(\d+)\s+\d+\s+([+-]?[0-9]*\.?[0-9]+)\s+([+-]?[0-9]*\.?[0-9]+)\s+([+-]?[0-9]*\.?[0-9]+)', [1, num_atoms])];
  29. intermediate_clusters = regexp(raw_data, intermediate_cluster_regexp, 'tokens');
  30. intermediate_clusters = cellfun(@str2num, [intermediate_clusters{:}]);
  31. steps = length(intermediate_clusters) / num_atoms / 4;
  32. % Also determine how many leading zeroes are necessary for correctly listing
  33. % the intermediate .xyz files.
  34. leading_zeroes = floor(log10(steps));
  35. previous_energy = 0;
  36. step_count = 0;
  37. xc_functional = regexp(raw_data, 'SCF Done:\s+E\((\w+)\)', 'tokens', 'once');
  38. xc_functional = xc_functional{1};
  39. % Extract the days, hours, minutes and seconds.
  40. cpu_time = regexp(raw_data,
  41. 'Job cpu time:\D+(\d+)\D+(\d+)\D+(\d+)\D+([0-9]*\.?[0-9]+)',
  42. 'tokens', 'once');
  43. % Convert to 'days:hours:minutes:seconds' format.
  44. cpu_time = [cpu_time{1} ':' cpu_time{2} ':' cpu_time{3} ':' cpu_time{4}];
  45. energy = regexp(raw_data, 'SCF Done:\s+E\(\w+\) = ([+-]?[0-9]*\.?[0-9]+)', 'tokens');
  46. energy = cellfun(@str2num, [energy{:}]);
  47. pct_change_in_energy = -diff(energy) ./ energy(1:end-1) * 100;
  48. cycles = regexp(raw_data, 'SCF Done:\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\d+)', 'tokens');
  49. cycles = cellfun(@str2num, [cycles{:}]);
  50. % Remember: intermediate_clusters has all atomic numbers and 3D locations in a flat matrix!
  51. % Parse wisely.
  52. xyz_format_str = ['%s%s%s_Step_%0' num2str(leading_zeroes) 'd.xyz'];
  53. for step = 1:steps
  54. xyz_name = sprintf(xyz_format_str, output_dir, filesep, file_name, step);
  55. xyz_id = fopen(xyz_name, 'w');
  56. fdisp(xyz_id, sprintf('%d\n', num_atoms));
  57. for atom = 1:num_atoms
  58. fdisp(xyz_id, sprintf('%d %f %f %f',
  59. intermediate_clusters((step - 1) * num_atoms * 4
  60. + (atom - 1) * 4
  61. + 1),
  62. intermediate_clusters((step - 1) * num_atoms * 4
  63. + (atom - 1) * 4
  64. + 2),
  65. intermediate_clusters((step - 1) * num_atoms * 4
  66. + (atom - 1) * 4
  67. + 3),
  68. intermediate_clusters((step - 1) * num_atoms * 4
  69. + (atom - 1) * 4
  70. + 4)));
  71. endfor
  72. fclose(xyz_id);
  73. endfor
  74. figure(1, 'position', get(0, 'screensize'), 'visible', 'off');
  75. subplot(2, 1, 1);
  76. plot(cycles, energy, 'o');
  77. xlabel('Cycles');
  78. ylabel('Energy (A.U.)');
  79. title(['Cycles at Different Energy Levels (Functional: ' xc_functional ')']);
  80. set(gca, 'fontsize', 16);
  81. set(gca, 'xdir', 'reverse');
  82. subplot(2, 1, 2);
  83. plot(cycles(2:end), pct_change_in_energy, 'o');
  84. xlabel('Cycles');
  85. ylabel('% Change in Energy (A.U.)');
  86. set(gca, 'fontsize', 16);
  87. set(gca, 'xdir', 'reverse');
  88. print([output_dir filesep file_name '_energy_graph.png']);
  89. hgsave([output_dir filesep file_name '_energy_graph.ofig']);
  90. set(gcf, 'visible', 'on');