diff --git a/Exercise_02/molecular_dynamics.py b/Exercise_02/molecular_dynamics.py index 5e516a8..3fa4a39 100644 --- a/Exercise_02/molecular_dynamics.py +++ b/Exercise_02/molecular_dynamics.py @@ -119,7 +119,7 @@ def kinetic(velocity): """ Computes the kenetic energy given a systems `velocity` state. """ - return (mass / 2.0) * jnp.linalg.norm(velocity, axis = 1).sum() + return (mass / 2.0) * (velocity**2).sum() @jit def step(position, velocity, acceleration, box_size, step_size): diff --git a/Exercise_02/task02.py b/Exercise_02/task02.py index ea0dd18..5235f19 100644 --- a/Exercise_02/task02.py +++ b/Exercise_02/task02.py @@ -99,15 +99,3 @@ if config.verbose: print( "Final Mean Forces: {:.4e} {:.4e} {:.4e}".format(*final_mean_forces)) print(f"Final Mean ||Forces||: {final_mean_fnorm:.4e}") print(f"Done: saved inital state to '{config.output}'") - -# # if a plot path is provided -# if not config.plot is None: -# from mpl_toolkits import mplot3d -# import matplotlib.pyplot as plt -# # new plot with 3D axis -# plt.figure() -# ax = plt.axes(projection = "3d") -# # create 3D position scatter plot -# ax.scatter(position[:, 0], position[:, 1], position[:, 2]) -# # and save to file -# plt.savefig(config.plot) diff --git a/Exercise_02/task04.py b/Exercise_02/task04.py index 793e489..1399c31 100644 --- a/Exercise_02/task04.py +++ b/Exercise_02/task04.py @@ -10,6 +10,15 @@ arg_parser = OptionParser(usage = usage) arg_parser.add_option("-i", "--input", action = "store", type = str, dest = "input", default = None, help = "input file path (required!)") +arg_parser.add_option("-A", "--outputA", action = "store", type = str, + dest = "outputA", default = "task04A.txt", + help = "first output file path (default: 'task04A.txt')") +arg_parser.add_option("-B", "--outputB", action = "store", type = str, + dest = "outputB", default = "task04B.txt", + help = "second output file path (default: 'task04B.txt')") +arg_parser.add_option("-s", "--cdf_sample_count", action = "store", type = int, + dest = "cdf_sample_count", default = 5, + help = "Radius interval sample count for CDF estimate (default: 5)") arg_parser.add_option("-a", "--animate", action = "store_true", dest = "animate", default = False, help = "creates an trajectory animation of the states in the input file") @@ -31,36 +40,109 @@ else: exit(-1) ################################################################################ -### task 3 / trajectory generation ### +### task 4 / post processing ### ################################################################################ # note, load module _after_ processing script parameters (no need to load all # of the heavy numeric modules if only usage or alike is needed) import numpy as np -import matplotlib.pyplot as plt -from mpl_toolkits import mplot3d from molecular_dynamics import iter_load, energy, kinetic -if config.animate: - # new plot with 3D axis - fig = plt.figure() - ax = fig.add_subplot(111, projection = "3d") -count = 0 -for (position, velocity), box_size in iter_load(config.input): - count += 1 - e_pot = energy(position, box_size) - e_kin = kinetic(velocity) - print(f"{count: >3} - {e_pot:10.5e} {e_kin:10.5e} {(e_pot + e_kin):10.5e}") +# counte the number of states (system snapshots) in the input file +nr_states = 0 +# first output file and collect some info used in the next analysis! +with open(config.outputA, "w") as output: + # iterate over all state snapshots stored in the `config.input` file + for (position, velocity), box_size in iter_load(config.input): + nr_states += 1 + # compute potneital and kinetic energy for current snapshot + e_pot = energy(position, box_size) + e_kin = kinetic(velocity) + # energy results + print(e_pot, e_kin, file = output) +# report file path +print(f"Saved energy change to '{config.outputA}'") - if config.animate: - ax.cla() - plt.title(f"time step {count}") - plt.xlim([0, box_size]) - plt.ylim([0, box_size]) - ax.set_zlim([0, box_size]) - # create 3D position scatter plot - position = np.mod(position, box_size) - ax.scatter(position[:, 0], position[:, 1], position[:, 2]) - # # and save to file - # plt.savefig(config.plot) - plt.pause(0.01) +# CDF radius sample points (`box_size` known from last loop) +radii = np.linspace(0, box_size / 2.0, config.cdf_sample_count)[np.newaxis, :] +# radius Commulative Distribution Function estimate +CDF = np.zeros((config.cdf_sample_count, )) + +# extract only one of two distance combinations of non-equal particles +lower_tri = np.tril_indices(position.shape[0], k = -1) +# maximum distance two particles (in folded space) can be apart +max_dist = box_size / 2.0 + +# second iteration to estimate pairwise distance CDF +for i, ((position, velocity), box_size) in enumerate(iter_load(config.input)): + # ignore the first 25% (just keep it simple) + if 4 * i < nr_states: + continue + # magic for all particle pair distances + diff = position[:, np.newaxis, :] - position + diff = diff[lower_tri[0], lower_tri[1], :] + # fold space in all directions. The `max_dist` is the maximum distance + # in the folded space untill the distance through the folded space + # border is smaller than inside the box. 3-axis parallel fold + diff = np.mod(diff + max_dist, box_size) - max_dist + # count nr particles pairs with distance smaller than r + dist = np.linalg.norm(diff, axis = 1) + # accumulate per timepoint partial mean estimates of the CDF + CDF += np.mean(dist[:, np.newaxis] < radii, axis = 0) +# final division by timesteps as mean over pairs and time. +CDF /= nr_states + +# store the CDF estimate to the second file +with open(config.outputB, "w") as output: + for r, cdf in zip(radii.ravel(), CDF.ravel()): + print(r, cdf, file = output) +# report file path +print(f"Saved radius CDF estimate to '{config.outputB}'") + + +# import matplotlib.pyplot as plt +# from mpl_toolkits import mplot3d + +# if config.animate: +# # new plot with 3D axis +# count = 0 +# fig = plt.figure() +# ax = fig.add_subplot(111, projection = "3d") + +# for (position, velocity), box_size in iter_load(config.input): +# e_pot = energy(position, box_size) +# e_kin = kinetic(velocity) +# print(f"{e_pot:10.5e} {e_kin:10.5e} {(e_pot + e_kin):10.5e}") + +# if config.animate: +# count += 1 +# ax.cla() +# plt.title(f"time step {count}") +# plt.xlim([0, box_size]) +# plt.ylim([0, box_size]) +# ax.set_zlim([0, box_size]) +# # create 3D position scatter plot +# position = np.mod(position, box_size) +# ax.scatter(position[:, 0], position[:, 1], position[:, 2]) +# # # and save to file +# # plt.savefig(config.plot) +# plt.pause(0.01) + + + +# import numpy as np +# import matplotlib.pyplot as plt +# from mpl_toolkits import mplot3d +# from molecular_dynamics import load, energy, kinetic + +# (position, velocity), box_size = load("task02.xyz"): + +# fig = plt.figure() +# ax = fig.add_subplot(111, projection = "3d") +# ax.cla() +# plt.xlim([0, box_size]) +# plt.ylim([0, box_size]) +# ax.set_zlim([0, box_size]) +# # create 3D position scatter plot +# position = np.mod(position, box_size) +# ax.scatter(position[:, 0], position[:, 1], position[:, 2]) diff --git a/Exercise_02_Assignment.pdf b/Exercise_02_Assignment.pdf new file mode 100644 index 0000000..3664e46 Binary files /dev/null and b/Exercise_02_Assignment.pdf differ