diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 35f4c7104d14fdb8a96ad0a2e0b05f6603c2ba7c..ebc6edfd08f8af1e5ebaa0d694015b67915852e8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,8 +15,8 @@ variables: # them in a virtualenv and cache it as well. cache: paths: - - .cache/pip - - venv/ + - .cache/pip + - venv/ before_script: - python -V # Print out python version for debugging @@ -36,8 +36,9 @@ vis.py: - python sim_controller.py "config/default.in" --no-figures - python vis.py "sim_output/default" --no-gui -vis.py multi: +vis.py all multi: script: - python sim_controller.py "config/default.in" --no-figures --compress - python sim_controller.py "config/default.in" --no-figures --compress - python vis.py "sim_output/default" --no-gui --all --multi + - python vis.py "sim_output/default" --no-gui --all --no-multi diff --git a/ase_sim.py b/ase_sim.py index 93b04f65aeae54a9f06ce026dd6b84bfe398d290..265315181c8f850c5429719f09fee77f38467d33 100644 --- a/ase_sim.py +++ b/ase_sim.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # ------------------------------ -# TODO: rename or merge with sim_controller or sim_creator? +# TODO: merge with sim_controller or sim_creator? import os import math diff --git a/config/Fe10Cr10Al_deep_200.in b/config/Fe10Cr10Al_deep_200.in index e691bcd0bc3a6ee0205b8e959e197638065e5711..bf4889c25d26fe9c599762b8daf7b8c2771f8d4d 100644 --- a/config/Fe10Cr10Al_deep_200.in +++ b/config/Fe10Cr10Al_deep_200.in @@ -22,6 +22,9 @@ pot_filename = potentials_deep.txt Cr = 0.10 Al = 0.10 +[Empty space dopants] +O = 0.001 + [Figure parameters] profile_mean_range = 200 profile_anim_range = True diff --git a/config/Fe10Cr20Al_normal_200_init-O.in b/config/Fe10Cr10Al_normal_100.in similarity index 85% rename from config/Fe10Cr20Al_normal_200_init-O.in rename to config/Fe10Cr10Al_normal_100.in index 6efbafee46278b4fe0e75e39592f5fde62d1b5b0..b3448eef6b91357c030f5c92b2e8dbe8f62375be 100644 --- a/config/Fe10Cr20Al_normal_200_init-O.in +++ b/config/Fe10Cr10Al_normal_100.in @@ -1,13 +1,13 @@ [Job parameters] -job_name = Fe10Cr20Al_normal_200_init-O +job_name = Fe10Cr10Al_normal_100 report_file = True [Simulation parameters] sim_type = ase_sim -kT = 200 +kT = 100 n_exchanges = 20000000 n_frames = 200 -rand_ox = False +rand_ox = True [Lattice parameters] bounds_scale = 25 @@ -20,10 +20,10 @@ pot_filename = potentials_normal.txt [Bulk dopants] Cr = 0.10 -Al = 0.20 +Al = 0.10 [Empty space dopants] -O = 0.10 +O = 0.001 [Figure parameters] profile_mean_range = 200 diff --git a/config/Fe10Cr10Al_normal_200.in b/config/Fe10Cr10Al_normal_200.in index f9bc9cc4a81c96985df2ef875d7e3bd9c10bbea4..ea65c4186c5229a772dcb09a577195c5be286042 100644 --- a/config/Fe10Cr10Al_normal_200.in +++ b/config/Fe10Cr10Al_normal_200.in @@ -22,6 +22,9 @@ pot_filename = potentials_normal.txt Cr = 0.10 Al = 0.10 +[Empty space dopants] +O = 0.001 + [Figure parameters] profile_mean_range = 200 profile_anim_range = True diff --git a/config/Fe10Cr10Al_normal_200_long.in b/config/Fe10Cr10Al_normal_200_long.in index b57f78f6633496b65f87bae68b6d3e00b5486102..8153fa11ea0365b88151eaf0ec47756d3fa0297b 100644 --- a/config/Fe10Cr10Al_normal_200_long.in +++ b/config/Fe10Cr10Al_normal_200_long.in @@ -22,6 +22,9 @@ pot_filename = potentials_normal.txt Cr = 0.10 Al = 0.10 +[Empty space dopants] +O = 0.001 + [Figure parameters] profile_mean_range = 200 profile_anim_range = True diff --git a/config/Fe10Cr20Al_normal-zero-O_200.in b/config/Fe10Cr10Al_normal_200_neg-O.in similarity index 78% rename from config/Fe10Cr20Al_normal-zero-O_200.in rename to config/Fe10Cr10Al_normal_200_neg-O.in index 8f2a114802c54b89f1c76f03ed020b8d317908af..42265d9d2d823b26c8bc24f81960c936a485f539 100644 --- a/config/Fe10Cr20Al_normal-zero-O_200.in +++ b/config/Fe10Cr10Al_normal_200_neg-O.in @@ -1,5 +1,5 @@ [Job parameters] -job_name = Fe10Cr20Al_normal-zero-O_200 +job_name = Fe10Cr10Al_normal_200_neg-O report_file = True [Simulation parameters] @@ -16,11 +16,14 @@ y_scale = 1 z_scale = 1 basis = Fe empty_space = 0.5 -pot_filename = potentials_normal-zero-O.txt +pot_filename = potentials_normal_neg-O.txt [Bulk dopants] Cr = 0.10 -Al = 0.20 +Al = 0.10 + +[Empty space dopants] +O = 0.001 [Figure parameters] profile_mean_range = 200 diff --git a/config/Fe10Cr10Al_normal_200_zero-O.in b/config/Fe10Cr10Al_normal_200_zero-O.in new file mode 100644 index 0000000000000000000000000000000000000000..d31ef0fc9d90f732cc4e647ba139e6dc19410c17 --- /dev/null +++ b/config/Fe10Cr10Al_normal_200_zero-O.in @@ -0,0 +1,37 @@ +[Job parameters] +job_name = Fe10Cr10Al_normal_200_zero-O +report_file = True + +[Simulation parameters] +sim_type = ase_sim +kT = 200 +n_exchanges = 20000000 +n_frames = 200 +rand_ox = True + +[Lattice parameters] +bounds_scale = 25 +x_scale = 1 +y_scale = 1 +z_scale = 1 +basis = Fe +empty_space = 0.5 +pot_filename = potentials_normal_zero-O.txt + +[Bulk dopants] +Cr = 0.10 +Al = 0.10 + +[Empty space dopants] +O = 0.001 + +[Figure parameters] +profile_mean_range = 200 +profile_anim_range = True +energy_range = True +diff_const = True +Fe = s,#e06633 +Cr = o,#8a99c7 +Al = ^,#bfa6a6 +O = D,#ff0d0d +X = x,#000000 diff --git a/config/Fe10Cr20Al_normal-neg-O_200.in b/config/Fe10Cr10Al_normal_400.in similarity index 78% rename from config/Fe10Cr20Al_normal-neg-O_200.in rename to config/Fe10Cr10Al_normal_400.in index ee0ad0b7d94b1f7ac42a22bdb3d0bff630f8b4ea..a64c34eb5b23e0b47895a98a43a2ab66fbb4e2c5 100644 --- a/config/Fe10Cr20Al_normal-neg-O_200.in +++ b/config/Fe10Cr10Al_normal_400.in @@ -1,10 +1,10 @@ [Job parameters] -job_name = Fe10Cr20Al_normal-neg-O_200 +job_name = Fe10Cr10Al_normal_400 report_file = True [Simulation parameters] sim_type = ase_sim -kT = 200 +kT = 400 n_exchanges = 20000000 n_frames = 200 rand_ox = True @@ -16,11 +16,14 @@ y_scale = 1 z_scale = 1 basis = Fe empty_space = 0.5 -pot_filename = potentials_normal-neg-O.txt +pot_filename = potentials_normal.txt [Bulk dopants] Cr = 0.10 -Al = 0.20 +Al = 0.10 + +[Empty space dopants] +O = 0.001 [Figure parameters] profile_mean_range = 200 diff --git a/config/Fe10Cr20Al_shallow_200.in b/config/Fe10Cr10Al_shallow_200.in similarity index 86% rename from config/Fe10Cr20Al_shallow_200.in rename to config/Fe10Cr10Al_shallow_200.in index b6f35504b1c7166110781fe89969a1d84917d30f..c204c1fed62fb44f6fca4ceeab10ac54e311d1c7 100644 --- a/config/Fe10Cr20Al_shallow_200.in +++ b/config/Fe10Cr10Al_shallow_200.in @@ -1,5 +1,5 @@ [Job parameters] -job_name = Fe10Cr20Al_shallow_200 +job_name = Fe10Cr10Al_shallow_200 report_file = True [Simulation parameters] @@ -20,7 +20,10 @@ pot_filename = potentials_shallow.txt [Bulk dopants] Cr = 0.10 -Al = 0.20 +Al = 0.10 + +[Empty space dopants] +O = 0.001 [Figure parameters] profile_mean_range = 200 diff --git a/config/Fe10Cr20Al_deep_200.in b/config/Fe10Cr20Al_deep_200.in index a2c8dd6192485b57f456faff45bf7b14af6e387a..38398d97423defbbd4c3d9dc59791220acf6d99f 100644 --- a/config/Fe10Cr20Al_deep_200.in +++ b/config/Fe10Cr20Al_deep_200.in @@ -22,6 +22,9 @@ pot_filename = potentials_deep.txt Cr = 0.10 Al = 0.20 +[Empty space dopants] +O = 0.001 + [Figure parameters] profile_mean_range = 200 profile_anim_range = True diff --git a/config/Fe10Cr20Al_normal-zero-O_200_long.in b/config/Fe10Cr20Al_normal-zero-O_200_long.in deleted file mode 100644 index 13a31e7a547a76c91c66c7e6d99cea057cb87af6..0000000000000000000000000000000000000000 --- a/config/Fe10Cr20Al_normal-zero-O_200_long.in +++ /dev/null @@ -1,34 +0,0 @@ -[Job parameters] -job_name = Fe10Cr20Al_normal-zero-O_200_long -report_file = True - -[Simulation parameters] -sim_type = ase_sim -kT = 200 -n_exchanges = 100000000 -n_frames = 200 -rand_ox = True - -[Lattice parameters] -bounds_scale = 25 -x_scale = 1 -y_scale = 1 -z_scale = 1 -basis = Fe -empty_space = 0.5 -pot_filename = potentials_normal-zero-O.txt - -[Bulk dopants] -Cr = 0.10 -Al = 0.20 - -[Figure parameters] -profile_mean_range = 200 -profile_anim_range = True -energy_range = True -diff_const = True -Fe = s,#e06633 -Cr = o,#8a99c7 -Al = ^,#bfa6a6 -O = D,#ff0d0d -X = x,#000000 diff --git a/config/Fe10Cr20Al_normal_200.in b/config/Fe10Cr20Al_normal_200.in index ca3615857c468256ed5374c79fb54afd54a16ef7..c94386f07e52876b4a6d3f5ee98dffa34a07e11b 100644 --- a/config/Fe10Cr20Al_normal_200.in +++ b/config/Fe10Cr20Al_normal_200.in @@ -22,6 +22,9 @@ pot_filename = potentials_normal.txt Cr = 0.10 Al = 0.20 +[Empty space dopants] +O = 0.001 + [Figure parameters] profile_mean_range = 200 profile_anim_range = True diff --git a/config/Fe10Cr20Al_normal_200_large.in b/config/Fe10Cr20Al_normal_200_large.in index df386bf9d12596455c0dbbcb5ac0bb2394866da1..f34894693cc101cac729f08f53f9e07e1335eb77 100644 --- a/config/Fe10Cr20Al_normal_200_large.in +++ b/config/Fe10Cr20Al_normal_200_large.in @@ -22,6 +22,9 @@ pot_filename = potentials_normal.txt Cr = 0.10 Al = 0.20 +[Empty space dopants] +O = 0.001 + [Figure parameters] profile_mean_range = 200 profile_anim_range = True diff --git a/config/Fe10Cr20Al_normal_200_long.in b/config/Fe10Cr20Al_normal_200_long.in index 0e0f87f25c7aa74b7aaadfa24cac5be128ddb6f7..c8ded1441ab43cdac978c11267f33008aad03df7 100644 --- a/config/Fe10Cr20Al_normal_200_long.in +++ b/config/Fe10Cr20Al_normal_200_long.in @@ -22,6 +22,9 @@ pot_filename = potentials_normal.txt Cr = 0.10 Al = 0.20 +[Empty space dopants] +O = 0.001 + [Figure parameters] profile_mean_range = 200 profile_anim_range = True diff --git a/config/Fe10Cr20Al_normal_200_short.in b/config/Fe10Cr20Al_normal_200_short.in index ced8fd86e844f10ac05f2c5c2214231b0f08aa33..4bd09191dd990691256f0472032a2b8863eb41dd 100644 --- a/config/Fe10Cr20Al_normal_200_short.in +++ b/config/Fe10Cr20Al_normal_200_short.in @@ -22,6 +22,9 @@ pot_filename = potentials_normal.txt Cr = 0.10 Al = 0.20 +[Empty space dopants] +O = 0.001 + [Figure parameters] profile_mean_range = 20 profile_anim_range = True diff --git a/config/Fe10Cr20Al_normal_anneal.in b/config/Fe10Cr20Al_normal_anneal.in index ed5d380e0f62f7f8cc21997e096379801d49b41b..ae5093eb2b87fb84ada57df9b5e718f962b39e59 100644 --- a/config/Fe10Cr20Al_normal_anneal.in +++ b/config/Fe10Cr20Al_normal_anneal.in @@ -25,6 +25,9 @@ pot_filename = potentials_normal.txt Cr = 0.10 Al = 0.20 +[Empty space dopants] +O = 0.001 + [Figure parameters] profile_mean_range = 200 profile_anim_range = True diff --git a/config/Fe13Al_normal_200.in b/config/Fe13Al_normal_200.in index bf53b1309471d383801e668869f8a679ba666c35..ed9718562a122920c217e141696b1ea1c722ae1a 100644 --- a/config/Fe13Al_normal_200.in +++ b/config/Fe13Al_normal_200.in @@ -21,6 +21,9 @@ pot_filename = potentials_normal.txt [Bulk dopants] Al = 0.13 +[Empty space dopants] +O = 0.001 + [Figure parameters] profile_mean_range = 200 profile_anim_range = True diff --git a/config/anim_test.in b/config/anim_test.in index 7376a1ad114b6ad2560e6b7647a9cc4b1f2026cf..dd3e23c5851505e733f5f0d3caeeb052f7a0fd56 100644 --- a/config/anim_test.in +++ b/config/anim_test.in @@ -22,6 +22,9 @@ pot_filename = potentials_original.txt Al = 0.10 Cr = 0.10 +[Empty space dopants] +O = 0.001 + [Figure parameters] profile_mean_range = >100 profile_anim_range = >10 diff --git a/config/default.in b/config/default.in index 5a26ec69946f999db6a368caf938cf1440172cb3..ceca80007ff1bc5deb2467afc9a8629a125d4cd5 100644 --- a/config/default.in +++ b/config/default.in @@ -6,7 +6,7 @@ report_file = True sim_type = ase_sim kT = 200 n_exchanges = 10000 -n_frames = 200 +n_frames = 20 rand_ox = True [Lattice parameters] @@ -23,11 +23,11 @@ Al = 0.10 Cr = 0.10 [Empty space dopants] -O = 0.00 +O = 0.001 [Figure parameters] profile_mean_range = 150-200 -profile_anim_range = False +profile_anim_range = True energy_range = True diff_const = True Fe = s,#e06633 diff --git a/config/dope_test.in b/config/dope_test.in index 77dd52e05f4ecee6612a1662065f9380957b6fe5..7f7a7ecab8be60c240cce7a205675af9854be14d 100644 --- a/config/dope_test.in +++ b/config/dope_test.in @@ -22,3 +22,6 @@ pot_filename = potentials_original.txt Al = 0.2 Cr = 0.2 X = 0.2 + +[Empty space dopants] +O = 0.001 diff --git a/config/figure_test.in b/config/figure_test.in index 248cf5f0be97544830db81dffb48e64416fcb4ee..553810ab18763651fdf7899111792f83b5f0e7a0 100644 --- a/config/figure_test.in +++ b/config/figure_test.in @@ -22,6 +22,9 @@ pot_filename = potentials_original.txt Cr = 0.10 Al = 0.05 +[Empty space dopants] +O = 0.001 + [Figure parameters] profile_mean_range = >50 profile_anim_range = All diff --git a/config/step_test.in b/config/step_test.in index 55257253d0735ddcd184bd1b2fd680e963b6ccee..1af4d6485b5d77e4105528ccf2621c59f914d385 100644 --- a/config/step_test.in +++ b/config/step_test.in @@ -21,5 +21,8 @@ pot_filename = potentials_original.txt Al = 0.05 Cr = 0.10 +[Empty space dopants] +O = 0.001 + [Empty space dopants] O = 0.1 diff --git a/data/potentials_deep.txt b/data/potentials_deep.txt index 3748d616c62da2896b794cc1de5e07a1f8e1e32a..59df58d63290c2bd790ce16947e2730da993e962 100644 --- a/data/potentials_deep.txt +++ b/data/potentials_deep.txt @@ -1,6 +1,6 @@ - Fe Cr Al O X -Fe -100 -100 -100 -200 100 -Cr -100 -100 -500 100 -Al -100 -2500 100 -O -200 100 -X 0 + Fe Cr Al O X +Fe -100 -100 -100 -200 100 +Cr -100 -100 -1000 100 +Al -100 -2500 100 +O -200 100 +X 0 diff --git a/data/potentials_normal-neg-O.txt b/data/potentials_normal-neg-O.txt deleted file mode 100644 index 57ec875fc9beb89164a73928c70b5e53e85d0090..0000000000000000000000000000000000000000 --- a/data/potentials_normal-neg-O.txt +++ /dev/null @@ -1,6 +0,0 @@ - Fe Cr Al O X -Fe -100 -100 -100 -200 100 -Cr -100 -100 -600 100 -Al -100 -900 100 -O -400 100 -X 0 diff --git a/data/potentials_normal-zero-O.txt b/data/potentials_normal-zero-O.txt deleted file mode 100644 index 5656ed5e1deaabdb9ccc504c91a4f9ceff21b0f4..0000000000000000000000000000000000000000 --- a/data/potentials_normal-zero-O.txt +++ /dev/null @@ -1,6 +0,0 @@ - Fe Cr Al O X -Fe -100 -100 -100 -200 100 -Cr -100 -100 -600 100 -Al -100 -900 100 -O 0 100 -X 0 diff --git a/data/potentials_normal.txt b/data/potentials_normal.txt index 0dbe341d2f845644077d5a1cf01dd550ff6ece62..263a6c124affc519f6786bd023e21638c6c16d00 100644 --- a/data/potentials_normal.txt +++ b/data/potentials_normal.txt @@ -1,6 +1,6 @@ - Fe Cr Al O X -Fe -100 -100 -100 -200 100 -Cr -100 -100 -600 100 -Al -100 -900 100 -O -200 100 -X 0 + Fe Cr Al O X +Fe -100 -100 -100 -200 100 +Cr -100 -100 -600 100 +Al -100 -900 100 +O -200 100 +X 0 diff --git a/data/potentials_normal_neg-O.txt b/data/potentials_normal_neg-O.txt new file mode 100644 index 0000000000000000000000000000000000000000..8509aad709bb9528b0354ba805bd78ee0fd38fec --- /dev/null +++ b/data/potentials_normal_neg-O.txt @@ -0,0 +1,6 @@ + Fe Cr Al O X +Fe -100 -100 -100 -200 100 +Cr -100 -100 -600 100 +Al -100 -900 100 +O -400 100 +X 0 diff --git a/data/potentials_normal_zero-O.txt b/data/potentials_normal_zero-O.txt new file mode 100644 index 0000000000000000000000000000000000000000..f806b619804b6d9e9d2d717e36c89da0b5127133 --- /dev/null +++ b/data/potentials_normal_zero-O.txt @@ -0,0 +1,6 @@ + Fe Cr Al O X +Fe -100 -100 -100 -200 100 +Cr -100 -100 -600 100 +Al -100 -900 100 +O 0 100 +X 0 diff --git a/data/potentials_original.txt b/data/potentials_original.txt index 274b0fc2b5d769fbe52ea44c257d67bc5d141b9c..5c5945d482fe167dda9188343c8bd28bd7e27c5e 100644 --- a/data/potentials_original.txt +++ b/data/potentials_original.txt @@ -1,6 +1,6 @@ - Fe Cr Al O X -Fe -20 -20 -20 0 10 -Cr -20 -20 -10 10 -Al -20 -20 10 -O 0 10 -X 0 + Fe Cr Al O X +Fe -20 -20 -20 0 10 +Cr -20 -20 -10 10 +Al -20 -20 10 +O 0 10 +X 0 diff --git a/data/potentials_shallow.txt b/data/potentials_shallow.txt index 52afd6744b90fe36b2f835971a03288af60e935f..2b34502747405a304427d37dcbe9308a8f5bf312 100644 --- a/data/potentials_shallow.txt +++ b/data/potentials_shallow.txt @@ -1,6 +1,6 @@ - Fe Cr Al O X -Fe -100 -100 -100 0 100 -Cr -100 -100 -200 100 -Al -100 -400 100 -O -100 100 -X 0 + Fe Cr Al O X +Fe -100 -100 -100 -200 100 +Cr -100 -100 -400 100 +Al -100 -600 100 +O -200 100 +X 0 diff --git a/sim_controller.py b/sim_controller.py index e064881bb6b4150d06b67a4a988ced5cf6d2b38c..f61774ae36bd662ce5cae05d82db583b1735a5fb 100644 --- a/sim_controller.py +++ b/sim_controller.py @@ -22,7 +22,6 @@ import os import shutil import sys import time -import zipfile from collections import OrderedDict import ase @@ -125,9 +124,9 @@ class SimController(object): for element, item in self.figure_params.items() if element in ase.data.chemical_symbols]) print("Drawing figures") - z_positions, dict_concs_mean, energy_list, frame_list = vis.read_plot_data(figure_out_path, - symbol_marker_color_dict, - figure_range_dict) + z_positions, dict_concs_mean, energy_list, frame_list = sim_utilities.read_conc_data(figure_out_path, + symbol_marker_color_dict, + figure_range_dict) vis.draw_figures(z_positions, dict_concs_mean, @@ -263,8 +262,8 @@ class SimController(object): diff_const_file.write(diff_const_file_line + "\n") diff_const_file.close() - def save_data(self, file_path): - data_matrix = [] + def save_conc(self, file_path): + conc_matrix = [] conc_file_header = "z " for symbol in self.symbol_marker_color_dict: conc_file_header += symbol + " " @@ -295,19 +294,19 @@ class SimController(object): conc = dict_concs_per_symbol_per_z[symbol][i] conc_file_line += str(conc) + " " conc_file_data_list.append(conc) - data_matrix.append(conc_file_data_list) + conc_matrix.append(conc_file_data_list) - # data_matrix = np.array(data_matrix) - np.savetxt(file_path, data_matrix, header=conc_file_header, fmt='%.6f') + # conc_matrix = np.array(conc_matrix) + np.savetxt(file_path, conc_matrix, header=conc_file_header, fmt='%.6f') def write_frame(self, i_str, job_out_path): - sim_data_folder_path = os.path.join(job_out_path, 'sim_data') - if not os.path.exists(sim_data_folder_path): - os.mkdir(sim_data_folder_path) + sim_frames_folder_path = os.path.join(job_out_path, 'sim_frames') + if not os.path.exists(sim_frames_folder_path): + os.mkdir(sim_frames_folder_path) sim_conc_folder_path = os.path.join(job_out_path, 'sim_conc') if not os.path.exists(sim_conc_folder_path): os.mkdir(sim_conc_folder_path) - sim_data_file_path = os.path.join(sim_data_folder_path, sim_data_filename.format(i=i_str)) + sim_frames_file_path = os.path.join(sim_frames_folder_path, sim_frames_filename.format(i=i_str)) sim_conc_file_path = os.path.join(sim_conc_folder_path, sim_conc_filename.format(i=i_str)) self.sim.atoms.info['kT'] = self.last_kT @@ -322,8 +321,8 @@ class SimController(object): energy_file.write("frame energy\n") with open(energy_file_path, 'a') as energy_file: energy_file.write(" ".join([i_str, str(self.sim.atoms.calc.results['energy']), "\n"])) - self.sim.write(sim_data_file_path) - self.save_data(sim_conc_file_path) + self.sim.write(sim_frames_file_path) + self.save_conc(sim_conc_file_path) def make_config_file(conf_filename='default.in'): @@ -336,7 +335,7 @@ def make_config_file(conf_filename='default.in'): conf_writer['Simulation parameters'] = OrderedDict((('sim_type', 'ase_sim'), ('kT', '200'), ('n_exchanges', '10000'), - ('n_frames', '200'), + ('n_frames', '20'), ('rand_ox', 'True'))) conf_writer['Lattice parameters'] = OrderedDict((('bounds_scale', '10'), ('x_scale', '1'), @@ -346,9 +345,9 @@ def make_config_file(conf_filename='default.in'): ('empty_space', '0.5'), ('pot_filename', 'potentials_normal.txt'))) conf_writer['Bulk dopants'] = OrderedDict((('Al', '0.10'), ('Cr', '0.10'))) - conf_writer['Empty space dopants'] = {'O': '0.00'} + conf_writer['Empty space dopants'] = {'O': '0.001'} conf_writer['Figure parameters'] = OrderedDict((('profile_mean_range', '150-200'), - ('profile_anim_range', 'False'), + ('profile_anim_range', 'True'), ('energy_range', 'True'), ('diff_const', 'True'), ('Fe', 's,#e06633'), @@ -424,12 +423,11 @@ for sim_ctrl in sim_controllers: job_out_path = sim_utilities.rename_existing_path(os.path.join(jobs_out_path, folder_time)) os.makedirs(job_out_path) - # TODO: do not assume folder for data shutil.copy(os.path.join('data', sim_ctrl.lattice_params['pot_filename']), os.path.join(job_out_path, sim_ctrl.lattice_params['pot_filename'])) shutil.copy(sim_ctrl.conf_filename, os.path.join(job_out_path, os.path.split(sim_ctrl.conf_filename)[1])) - sim_data_filename = 'frame-{i}.xyz' + sim_frames_filename = 'frame-{i}.xyz' sim_conc_filename = 'frame-{i}.txt' n_frames_width = len(str(sim_ctrl.sim_params['n_frames'])) @@ -476,10 +474,10 @@ for sim_ctrl in sim_controllers: # update console two times per second if time.time() - print_time >= 0.5: - print("\rWrote frame {i}/{n}".format(i=i_str, n=str(sim_ctrl.sim_params['n_frames'])), end="") + print("\rWrote frame {i}/{n}".format(i=i_str, n=sim_ctrl.sim_params['n_frames']), end="") print_time = time.time() - print("\rWrote frame {}/{}".format(str(sim_ctrl.sim_params['n_frames']), str(sim_ctrl.sim_params['n_frames'])), + print("\rWrote frame {}/{}".format(sim_ctrl.sim_params['n_frames'], sim_ctrl.sim_params['n_frames']), flush=True) end_time = time.time() sim_ctrl.sim_time = sim_utilities.format_time(end_time - start_time) @@ -496,8 +494,6 @@ for sim_ctrl in sim_controllers: # ------------------------------ if not arguments.no_figures and sim_ctrl.figure_params: - # TODO: do not duplicate code - figure_range_dict = sim_utilities.parse_figure_range_str(sim_ctrl.figure_params) if len([fig_range for fig_range in figure_range_dict.values() if fig_range is not False]) > 0 or \ @@ -507,16 +503,7 @@ for sim_ctrl in sim_controllers: if arguments.compress: print("Compressing frames...", end="") sys.stdout.flush() - frames_zipfile = zipfile.ZipFile(os.path.join(job_out_path, 'sim_data.zip'), 'w', - compression=zipfile.ZIP_DEFLATED) - sim_data_folder_path = os.path.join(job_out_path, 'sim_data') - for filename in os.listdir(sim_data_folder_path): - frames_zipfile.write(os.path.join(sim_data_folder_path, filename), os.path.join('sim_data', filename)) - os.remove(os.path.join(sim_data_folder_path, filename)) - frames_zipfile.testzip() - frames_zipfile.close() - os.rmdir(sim_data_folder_path) - + sim_utilities.compress_frames(job_out_path) print("OK") print("") diff --git a/sim_utilities.py b/sim_utilities.py index c3f97d6a4c6f63420c0b047770fff4134e019f70..52cf9c005949ef18482d9ad124dedb19bd6a48f3 100644 --- a/sim_utilities.py +++ b/sim_utilities.py @@ -19,16 +19,51 @@ import configparser import math import os +import zipfile from collections import OrderedDict import ase import numpy as np +def average_filter_function(data): + """ + Applies a 3-wide average filter to data to make it smoother. + + :param data: the list of data to filter + :return: filtered data + """ + temp_data = [] + for i in range(len(data)): + sum = data[i] + if i == 0: + sum += data[i] + data[i + 1] + elif i == len(data) - 1: + sum += data[i - 1] + data[i] + else: + sum += data[i - 1] + data[i + 1] + temp_data.append(sum / 3) + return temp_data + + class ParsingError(Exception): pass +def compress_frames(job_out_path): + data_name = 'sim_frames' + frames_zipfile = zipfile.ZipFile(os.path.join(job_out_path, data_name + '.zip'), 'w', + compression=zipfile.ZIP_DEFLATED) + sim_frames_folder_path = os.path.join(job_out_path, data_name) + for filename in os.listdir(sim_frames_folder_path): + frames_zipfile.write(os.path.join(sim_frames_folder_path, filename), os.path.join(data_name, filename)) + frames_zipfile.testzip() + os.remove(os.path.join(sim_frames_folder_path, filename)) + frames_zipfile.close() + os.rmdir(sim_frames_folder_path) + + +# TODO: combine all three range parsing methods def convert_bool_to_range(range_list): if range_list is True: return [(0, math.inf)] @@ -111,23 +146,21 @@ def parse_conf(conf_filename): # n_exchanges and kT single_value_keys = {'n_exchanges', 'kT'} multiple_value_keys = {'n_steps_high', 'n_steps_fall', 'n_steps_low', 'kT_high', 'kT_low'} - - if not single_value_keys.issubset(sim_params.keys()) and \ - not multiple_value_keys.issubset(sim_params.keys()): + if not single_value_keys.issubset(sim_params.keys()) and not multiple_value_keys.issubset(sim_params.keys()): sim_params['n_exchanges'] = default_reader['Simulation parameters']['n_exchanges'] sim_params['kT'] = default_reader['Simulation parameters']['kT'] # constant values if single_value_keys.issubset(sim_params.keys()): sim_params['n_exchanges'] = int(sim_params['n_exchanges']) - n_steps_per_frame = int(sim_params['n_exchanges'] / sim_params['n_frames']) sim_params['kT'] = int(sim_params['kT']) # annealing elif multiple_value_keys.issubset(sim_params.keys()): sim_params['n_exchanges'] = [int(sim_params['n_steps_high']), int(sim_params['n_steps_fall']), int(sim_params['n_steps_low'])] - n_steps_per_frame = int(sum(sim_params['n_exchanges']) / sim_params['n_frames']) sim_params['kT'] = [int(sim_params['kT_high']), int(sim_params['kT_low'])] + else: + raise ParsingError("Unrecognized kT definition.") # rand_ox if 'rand_ox' not in sim_params.keys(): @@ -193,7 +226,6 @@ def parse_conf(conf_filename): figure_params = None return job_params, sim_params, lattice_params, bulk_dopants, empty_space_dopants, figure_params -# TODO: combine all three range parsing methods def parse_figure_range_str(figure_params): @@ -201,7 +233,6 @@ def parse_figure_range_str(figure_params): figure_str_list = ['profile_mean_range', 'profile_anim_range', 'energy_range'] # TODO: merge with vis - # TODO: support for '1-200, true' for figure_str in figure_str_list: if figure_str in figure_params.keys(): figure_range = figure_params[figure_str] @@ -226,10 +257,11 @@ def parse_param_str_to_bool(parameter): elif parameter.lower() in ['false', 'f', 'no', 'n', 'off', 'none']: return False else: - # TODO: specify file somehow; raise without message and catch in outer context? + # TODO: specify file name somehow; raise without message and catch in outer context? raise ParsingError('unknown boolean type: "{}"'.format(parameter)) +# TODO: combine all three range parsing methods def parse_range_str(parameter, lim_min=0, lim_max=math.inf): """ Converts a range specified in a string into a list of upper and lower bounds. @@ -255,6 +287,7 @@ def parse_range_str(parameter, lim_min=0, lim_max=math.inf): return ids +# TODO: combine all three range parsing methods def range_list_to_indexes(ranges, indexes): ids = set() for index in indexes: @@ -271,6 +304,84 @@ def range_list_to_indexes(ranges, indexes): return sorted(list(ids)) +def read_conc_data(in_path, symbol_marker_color_dict, figure_range_dict): + # ------------------------------ + # CALCULATING MEAN + # ------------------------------ + # TODO: make easier to understand + # TODO: stop shadowing names from outer scope + frame_list = [] + dict_concs_per_element = {} + energy_list = [] + z_positions = [] + + # read concentrations + conc_path = os.path.join(in_path, "sim_conc") + file_list = [entry for entry in os.listdir(conc_path) if entry.endswith(".txt")] + + with open(os.path.join(in_path, "energy.txt"), 'r') as energy_file: + energy_file_header = energy_file.readline() + while True: + energy_file_line = energy_file.readline() + if energy_file_line == "": + break + + energy_list.append(float(energy_file_line.split()[1])) + + for filename in file_list: + conc_file_path = os.path.join(conc_path, filename) + with open(conc_file_path, 'r') as conc_file: + symbols = conc_file.readline().split()[2:] + dict_concs_per_z = {} + for symbol1, symbol2 in zip(symbols, symbol_marker_color_dict): + dict_concs_per_z[symbol1] = [] + + if not symbol1 == symbol2: + raise Exception + + while True: + conc_file_line = conc_file.readline() + if conc_file_line == "": + break + + values = conc_file_line.split() + z_pos = float(values.pop(0)) + if z_pos not in z_positions: + z_positions.append(z_pos) + + for symbol, value in zip(symbol_marker_color_dict, values): + dict_concs_per_z[symbol].append(float(value)) + + frame_list.append(dict_concs_per_z) + + # convert list of frame data to lists of data per element + for i, dict_concs_per_z in enumerate(frame_list): + for symbol, concs_list in dict_concs_per_z.items(): + if symbol not in dict_concs_per_element.keys(): + dict_concs_per_element[symbol] = [] + for z_pos in z_positions: + dict_concs_per_element[symbol].append([]) + for i, z_pos in enumerate(z_positions): + dict_concs_per_element[symbol][i].append(concs_list[i]) + + # collect the average concentrations into a list per symbol and z-level + dict_concs_mean = {} + profile_mean_range = figure_range_dict['profile_mean_range'] + for symbol, concs_list in dict_concs_per_element.items(): + if symbol not in dict_concs_mean.keys(): + dict_concs_mean[symbol] = [0] * len(z_positions) + for z, concs in enumerate(concs_list): + indexes = range_list_to_indexes(profile_mean_range, range(len(concs))) + array_mask = [True] * len(concs) + for i, _ in enumerate(concs): + if i in indexes: + array_mask[i] = False + masked_concs = np.ma.array(concs, mask=array_mask) + dict_concs_mean[symbol][z] = np.mean(masked_concs) + + return z_positions, dict_concs_mean, energy_list, frame_list + + def read_job_name_and_end_energy(report_file): energy_report_str = "Final potential energy: " job_name = report_file.readline() @@ -352,7 +463,7 @@ def single_xyz_anim_to_multiple(filename): atomlines = [] for i in range(int(num_atoms)): atomlines.append(sim_output_file.readline()) - sim_frame_file = open(os.path.join("sim_data", "frame-{frame}.xyz".format(frame=frame)), "w") + sim_frame_file = open(os.path.join("sim_frames", "frame-{frame}.xyz".format(frame=frame)), "w") sim_frame_file.write(num_atoms + comment) for atomline in atomlines: sim_frame_file.write(atomline) @@ -361,4 +472,4 @@ def single_xyz_anim_to_multiple(filename): else: break - sim_output_file.close() \ No newline at end of file + sim_output_file.close() diff --git a/vis.py b/vis.py index e0cb73bdefa433fc5f22a45f18f3e1fb100a5a34..c4e6bb660774efbc92e5dfdddc4f79d9892c82a7 100644 --- a/vis.py +++ b/vis.py @@ -17,7 +17,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # ------------------------------ import os -import math import argparse # import matplotlib.animation as ani @@ -30,104 +29,6 @@ import ase import sim_utilities -def average_filter_function(data): - """ - Applies a 3-wide average filter to data to make it smoother. - - :param data: the list of data to filter - :return: filtered data - """ - temp_data = [] - for i in range(len(data)): - sum = data[i] - if i == 0: - sum += data[i] + data[i + 1] - elif i == len(data) - 1: - sum += data[i - 1] + data[i] - else: - sum += data[i - 1] + data[i + 1] - temp_data.append(sum / 3) - return temp_data - - -def read_plot_data(in_path, symbol_marker_color_dict, figure_range_dict): - # ------------------------------ - # CALCULATING MEAN - # ------------------------------ - # TODO: make easier to understand - # TODO: stop shadowing names from outer scope - frame_list = [] - dict_concs_per_element = {} - energy_list = [] - z_positions = [] - - # read concentrations - conc_path = os.path.join(in_path, "sim_conc") - file_list = [entry for entry in os.listdir(conc_path) if entry.endswith(".txt")] - - with open(os.path.join(in_path, "energy.txt"), 'r') as energy_file: - energy_file_header = energy_file.readline() - while True: - energy_file_line = energy_file.readline() - if energy_file_line == "": - break - - energy_list.append(float(energy_file_line.split()[1])) - - for filename in file_list: - conc_file_path = os.path.join(conc_path, filename) - with open(conc_file_path, 'r') as conc_file: - symbols = conc_file.readline().split()[2:] - dict_concs_per_z = {} - for symbol1, symbol2 in zip(symbols, symbol_marker_color_dict): - dict_concs_per_z[symbol1] = [] - - if not symbol1 == symbol2: - raise Exception - - while True: - conc_file_line = conc_file.readline() - if conc_file_line == "": - break - - values = conc_file_line.split() - z_pos = float(values.pop(0)) - if z_pos not in z_positions: - z_positions.append(z_pos) - - for symbol, value in zip(symbol_marker_color_dict, values): - dict_concs_per_z[symbol].append(float(value)) - - frame_list.append(dict_concs_per_z) - - # convert list of frame data to lists of data per element - for i, dict_concs_per_z in enumerate(frame_list): - for symbol, concs_list in dict_concs_per_z.items(): - if symbol not in dict_concs_per_element.keys(): - dict_concs_per_element[symbol] = [] - for z_pos in z_positions: - dict_concs_per_element[symbol].append([]) - for i, z_pos in enumerate(z_positions): - dict_concs_per_element[symbol][i].append(concs_list[i]) - - # collect the average concentrations into a list per symbol and z-level - dict_concs_mean = {} - profile_mean_range = figure_range_dict['profile_mean_range'] - for symbol, concs_list in dict_concs_per_element.items(): - if symbol not in dict_concs_mean.keys(): - dict_concs_mean[symbol] = [0] * len(z_positions) - for z, concs in enumerate(concs_list): - indexes = sim_utilities.range_list_to_indexes(profile_mean_range, range(len(concs))) - array_mask = [True] * len(concs) - for i, _ in enumerate(concs): - if i in indexes: - array_mask[i] = False - masked_concs = np.ma.array(concs, mask=array_mask) - dict_concs_mean[symbol][z] = np.mean(masked_concs) - - return z_positions, dict_concs_mean, energy_list, frame_list - - def draw_figures(z_positions, dict_concs_mean, energy_list, frame_list, fig_range_dict, symbol_marker_color_dict, no_gui, average_filter, out_path): import matplotlib if no_gui: @@ -149,7 +50,7 @@ def draw_figures(z_positions, dict_concs_mean, energy_list, frame_list, fig_rang # ------------------------------ # DRAWING FIGURES # ------------------------------ - # TODO: change if to functions + # TODO: change if to functions? # ------------------------------ # MEAN FIGURE # ------------------------------ @@ -179,7 +80,7 @@ def draw_figures(z_positions, dict_concs_mean, energy_list, frame_list, fig_rang # draw on filtered figure if average_filter: plt.figure(figure_mean_filtered.number) - plt.plot(z_positions, average_filter_function(data), marker=marker, color=color, label=label, + plt.plot(z_positions, sim_utilities.average_filter_function(data), marker=marker, color=color, label=label, zorder=2) # set mean figure appearance and save it plt.figure(figure_mean.number) @@ -227,7 +128,7 @@ def draw_figures(z_positions, dict_concs_mean, energy_list, frame_list, fig_rang atom_dict_concs = frame_list[0] data = atom_dict_concs[symbol] if average_filter: - data = average_filter_function(data) + data = sim_utilities.average_filter_function(data) line = plt.plot(z_positions, data, marker=marker, color=color, label=label, zorder=2) lines.append((symbol, line[0])) @@ -251,7 +152,7 @@ def draw_figures(z_positions, dict_concs_mean, energy_list, frame_list, fig_rang for symbol, line in lines: data = atom_dict_concs[symbol] if average_filter: - data = average_filter_function(data) + data = sim_utilities.average_filter_function(data) line.set_data(z_positions, data) figure_anim.set_size_inches(7, 7) n_frames_width = len(str(len(frame_list))) @@ -332,6 +233,7 @@ if __name__ == '__main__': arg_parser.add_argument('job_path', help='path to a finished job') arg_parser.add_argument('--all', action='store_true', help='plot all found jobs') arg_parser.add_argument('--multi', action='store_true', help='combine concentrations from multiple simulations') + arg_parser.add_argument('--no-multi', action='store_true', help='plot each simulation separately') arg_parser.add_argument('--no-gui', action='store_true', help='draw the figures only to files') arg_parser.add_argument('--average-filter', action='store_true', help='apply a filter to smooth the concentration profile') @@ -395,6 +297,10 @@ if __name__ == '__main__': if arguments.multi: multi_enable = True + print("Plotting combined concentrations from all simulations.") + elif arguments.no_multi: + multi_enable = False + print("Plotting all simulations separately.") else: multi_enable = False if len(job_selection) > 1: @@ -415,13 +321,6 @@ if __name__ == '__main__': multi_combined_energy_list.append([]) if multi_enable: - # TODO: is this needed? only jobs with the same name are accepted - for job_frame_numbers1 in job_frame_numbers_list: - for job_frame_numbers2 in job_frame_numbers_list: - if job_frame_numbers1 != job_frame_numbers2: - print("Jobs do not have the same length.") - exit(2) - multi_folder = "multi plot from {} to {}".format(os.path.basename(job_paths[job_selection[0]]), os.path.basename(job_paths[job_selection[-1]])) multi_path = sim_utilities.rename_existing_path(os.path.join(job_path, multi_folder)) @@ -430,6 +329,13 @@ if __name__ == '__main__': multi_report_file = open(os.path.join(multi_path, "multi_report.txt"), "w") multi_report_file.write("List of included simulations:\n") + # TODO: is this needed? only jobs with the same name are accepted + for job_frame_numbers1 in job_frame_numbers_list: + for job_frame_numbers2 in job_frame_numbers_list: + if job_frame_numbers1 != job_frame_numbers2: + print("Jobs do not have the same length.") + exit(2) + for job_index in job_selection: if job_index not in job_indices: raise IndexError("List index out of range.") @@ -456,10 +362,12 @@ if __name__ == '__main__': symbol_marker_color_dict = OrderedDict([(element, (item.split(',')[0], item.split(',')[1])) for element, item in figure_params.items() if element in ase.data.chemical_symbols]) - z_positions, dict_concs_mean, energy_list, frame_list = read_plot_data(sim_path, - symbol_marker_color_dict, - figure_range_dict) + z_positions, dict_concs_mean, \ + energy_list, frame_list = sim_utilities.read_conc_data(sim_path, + symbol_marker_color_dict, + figure_range_dict) if not multi_enable: + print("Drawing figures for {}...".format(os.path.basename(sim_path)), end="") draw_figures(z_positions, dict_concs_mean, energy_list, @@ -469,8 +377,9 @@ if __name__ == '__main__': arguments.no_gui, arguments.average_filter, sim_path) - - if multi_enable: + print("OK") + else: + print("Collecting data from {}...".format(os.path.basename(sim_path)), end="") # go through the list of frames and collect the concentrations for this simulation # and add them to a combined list per z per symbol per frame for i_frame, frame in enumerate(frame_list): @@ -499,10 +408,12 @@ if __name__ == '__main__': multi_combined_dict_concs_mean[symbol][i_z_pos].append(conc) multi_report_file.write("{}\n".format(os.path.basename(sim_path))) + print("OK") figure_range_dict["diff_const"] = False if multi_enable: + print("Drawing combined plot...", end="") for i_frame, frame in enumerate(frame_list): for symbol, conc_per_z in frame.items(): for i_z_pos, conc in enumerate(conc_per_z): @@ -523,3 +434,4 @@ if __name__ == '__main__': multi_path) multi_report_file.close() + print("OK")