graph_potential.m 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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. clear -global;
  17. % Let user select input file.
  18. [input_file, file_path] = uigetfile({'*.xyz*', 'Supported file formats'});
  19. % Load the input file.
  20. raw_data = fileread([file_path input_file]);
  21. [~, file_name, ~] = fileparts(input_file);
  22. % Let the user input the desired resolution and distance from structure.
  23. resolution = inputdlg('# of faces surrounding the sphere', 'Resolution');
  24. resolution = str2num(resolution{1});
  25. radius = inputdlg('Distance from structure', 'Radius');
  26. radius = str2num(radius{1});
  27. cd_regexp = ['Cd' repmat('\s+([+-]?[0-9]*\.?[0-9]+)', [1,3])];
  28. cd_locations = [regexp(raw_data, cd_regexp, 'tokens'){:}];
  29. cd_locations = reshape(sscanf(sprintf('%s ', cd_locations{:}), '%f'),
  30. 3, numel(cd_locations) / 3);
  31. se_regexp = ['Se' repmat('\s+([+-]?[0-9]*\.?[0-9]+)', [1,3])];
  32. se_locations = [regexp(raw_data, se_regexp, 'tokens'){:}];
  33. se_locations = reshape(sscanf(sprintf('%s ', se_locations{:}), '%f'),
  34. 3, numel(se_locations) / 3);
  35. % Get bounds for the grid.
  36. [x_min, x_max] = bounds([cd_locations(1,:), se_locations(1,:)]);
  37. x_mid = mean([x_min, x_max]);
  38. [y_min, y_max] = bounds([cd_locations(2,:), se_locations(2,:)]);
  39. y_mid = mean([y_min, y_max]);
  40. [z_min, z_max] = bounds([cd_locations(3,:), se_locations(3,:)]);
  41. z_mid = mean([z_min, z_max]);
  42. base_radius = max([x_max - x_mid, y_max - y_mid, z_max - z_mid]) * 2;
  43. radius += base_radius;
  44. radii = 0.1:0.1:radius;
  45. spheres = cell(1, length(radii));
  46. loading_bar = waitbar(0, 'Generating spheres...');
  47. for s = 1:length(spheres)
  48. tic;
  49. [X, Y, Z] = sphere(resolution);
  50. bench(s) = toc;
  51. X = radii(s) * X + x_mid;
  52. Y = radii(s) * Y + y_mid;
  53. Z = radii(s) * Z + z_mid;
  54. spheres{s} = {X, Y, Z};
  55. waitbar(s / length(spheres), loading_bar);
  56. endfor
  57. function [cd_distances, se_distances, potentials] = calc_potential(cd_locations,
  58. se_locations,
  59. X, Y, Z)
  60. potentials = zeros(size(X));
  61. q_e = 1.6021766208e-19;
  62. eps0 = 8.854187817e-12;
  63. kC = 1/(4*pi*eps0);
  64. cd_charge = 2 * q_e;
  65. se_charge = -2 * q_e;
  66. cd_distances = zeros(numel(X), length(cd_locations));
  67. se_distances = zeros(numel(X), length(se_locations));
  68. for ii = 1:length(cd_locations)
  69. potentials += cd_charge ./ hypot(cd_locations(1,ii) - X,
  70. cd_locations(2,ii) - Y,
  71. cd_locations(3,ii) - Z);
  72. endfor
  73. for ii = 1:length(se_locations)
  74. potentials += se_charge ./ hypot(se_locations(1,ii) - X,
  75. se_locations(2,ii) - Y,
  76. se_locations(3,ii) - Z);
  77. endfor
  78. potentials *= kC;
  79. potentials(potentials > 1) = NaN;
  80. endfunction
  81. cd_distances = se_distances = potentials = cell(1, length(spheres));
  82. waitbar(0, loading_bar, 'Calculating electrostatic potential on each sphere...');
  83. for s = 1:length(spheres)
  84. [cd_distances{s}, se_distances{s}, potentials{s}] = ...
  85. calc_potential(cd_locations, se_locations,
  86. spheres{s}{1}, spheres{s}{2}, spheres{s}{3});
  87. waitbar(s / length(spheres), loading_bar);
  88. endfor
  89. close(loading_bar);
  90. global g_potentials = potentials;
  91. % Make a new layer of potential calculations visible.
  92. function redraw_potential (handle, event)
  93. val = round(get(handle, 'value'));
  94. set(handle, 'value', val);
  95. global surfaces;
  96. global g_potentials;
  97. p = [g_potentials{val}](:);
  98. p = p(~isnan(p));
  99. caxis([min(p), max(p)]);
  100. cellfun(@(s) set(s, 'visible', 'off'), surfaces);
  101. set(surfaces{val}, 'visible', 'on');
  102. drawnow();
  103. endfunction
  104. % Takes "cd_locations" and "se_locations" matrices, and "spheres" and
  105. % "potentials" cell arrays.
  106. function f = plot_potential (cd_locations, se_locations, spheres, potentials)
  107. f = figure('Units', 'normalized',
  108. 'Position', [0.1, 0.1, 0.7, 0.7],
  109. 'visible', 'off');
  110. hold on;
  111. xlabel('X');
  112. ylabel('Y');
  113. zlabel('Z');
  114. title('Electrostatic potential (vastly oversimplified calculation)');
  115. scatter3(cd_locations(1,:), cd_locations(2,:), cd_locations(3,:),
  116. 100, [0, 1, 0], '^', 'filled');
  117. scatter3(se_locations(1,:), se_locations(2,:), se_locations(3,:),
  118. 100, [1, 0, 0], 'filled');
  119. global surfaces = cell(1, length(spheres));
  120. loading_bar = waitbar(0, 'Plotting spheres...');
  121. for ii = 1:length(surfaces)
  122. surfaces{ii} = surf(spheres{ii}{1},
  123. spheres{ii}{2},
  124. spheres{ii}{3},
  125. potentials{ii});
  126. set(surfaces{ii}, 'visible', 'off', 'facealpha', 0.5);
  127. waitbar(ii / length(surfaces), loading_bar);
  128. endfor
  129. set(surfaces{end}, 'visible', 'on');
  130. colormap(flipud(jet));
  131. colorbar;
  132. p = [potentials{end}](:);
  133. p = p(~isnan(p));
  134. caxis([min(p), max(p)]);
  135. axis('auto', 'equal');
  136. rotate3d on;
  137. grid;
  138. view(3);
  139. hold off;
  140. hslider = uicontrol('parent', f,
  141. 'style', 'slider',
  142. 'Units', 'normalized',
  143. 'position', [0.1, 0.025, 0.8, 0.025],
  144. 'min', 1,
  145. 'max', length(spheres),
  146. 'value', length(spheres),
  147. 'sliderstep', [1/length(spheres), 10/length(spheres)],
  148. 'callback', @redraw_potential);
  149. close(loading_bar);
  150. set(f, 'visible', 'on');
  151. endfunction
  152. fig = plot_potential(cd_locations, se_locations, spheres, potentials);
  153. waitfor(fig);