def test_same_minima_Frenkel(self): nparticles = 32 hs_radii = 0.05 * np.random.randn(nparticles) + 1 volpart = np.sum(4. / 3. * np.pi * hs_radii**3) phi = 0.7 boxl = (volpart / phi)**(1 / 3.) boxv = [boxl, boxl, boxl] coords = np.random.rand(nparticles * 3) * boxl ncellx_scale = get_ncellsx_scale(np.ones(nparticles), boxv) pot_cellists = Frenkel(boxvec=boxv, celllists=True, ncellx_scale=ncellx_scale) pot_no_cellists = Frenkel(boxvec=boxv, celllists=False, ncellx_scale=ncellx_scale) nsteps = 1000 tol = 1e-5 res_cell_lists = lbfgs_cpp(coords, pot_cellists, nsteps=nsteps, tol=tol) res_no_cell_lists = lbfgs_cpp(coords, pot_no_cellists, nsteps=nsteps, tol=tol) fcoords_cell_lists = res_cell_lists.coords fcoords_no_cell_lists = res_no_cell_lists.coords # self.assertEqual(fcoords_no_cell_lists,fcoords_cell_lists) self.assertTrue(np.all(fcoords_no_cell_lists == fcoords_cell_lists))
def generate_save_secondary_params(par, folder): """ TODO: rename to reflect this is for a binary system Generates a list of secondary parameters hs_radii, boxlength and scale and initial coords and saves them to the folder """ np.random.seed(0) # hs_radii = (par.radius_std.value * # np.random.randn(par.n_part.value) # + par.radius_mean.value) # for binary mixture npart_by_2 = par.n_part.value // 2 # NOTE: TODO: bug fix seeds hs_radii = np.array( list(par.r1.value + par.rstd1.value * np.random.randn(npart_by_2)) + list(par.r2.value + par.rstd2.value * np.random.randn(par.n_part.value - npart_by_2))) print(hs_radii, "hs_radii") print(len(hs_radii), "nparts") box_length = get_box_length(hs_radii, par.ndim.value, par.phi.value) print(box_length, "box_length") # initial coords are present, to keep continuity with previous code. but they are not necessary initial_coords = np.random.rand( par.n_part.value * par.ndim.value) * box_length print(initial_coords, "initial coords") print(get_ncellsx_scale(hs_radii, [box_length, box_length, box_length]), "cell scale") print(len(initial_coords), "initial_coords length") np.savetxt(folder + "/hs_radii.txt", hs_radii, delimiter=",") np.savetxt(folder + "/initial_coords.txt", initial_coords, delimiter=",") np.savetxt(folder + "/box_length.txt", [box_length], delimiter=",")
def generate_save_run_params_ip_binary(par, folder, seed=0): """ Generates and saves the run parameters. Creates a new folder called sec_params if it does not exist and a subfolder defined by the seed Parameters ---------- par : SystemParamInversePowerBinary System defining the parameters folder : str Folder defining our system seed : int, optional seed for generating random parameters """ np.random.seed(seed) # for binary mixture npart_by_2 = par.n_part.value // 2 hs_radii = np.array( list(par.r1.value + par.rstd1.value * np.random.randn(npart_by_2)) + list(par.r2.value + par.rstd2.value * np.random.randn(par.n_part.value - npart_by_2))) print(hs_radii, "hs_radii") print(len(hs_radii), "nparts") box_length = get_box_length(hs_radii, par.ndim.value, par.phi.value) print(box_length, "box_length") # initial coords are present, to keep continuity with previous code. but they are not necessary initial_coords = np.random.rand( par.n_part.value * par.ndim.value) * box_length print(initial_coords, "initial coords") print(get_ncellsx_scale(hs_radii, [box_length, box_length, box_length]), "cell scale") print(len(initial_coords), "initial_coords length") os.makedirs(folder + "/" + "sec_params" + "/" + str(seed), exist_ok=True) np.savetxt( folder + "/" + "sec_params" + "/" + str(seed) + "/hs_radii.txt", hs_radii, delimiter=",", ) np.savetxt( folder + "/" + "sec_params" + "/" + str(seed) + "/initial_coords.txt", initial_coords, delimiter=",", ) np.savetxt( folder + "/" + "sec_params" + "/" + str(seed) + "/box_length.txt", [box_length], delimiter=",", )
def test_same_minima_HS_WCA(self): nparticles = 32 radius_sca = 0.9085602964160698 pot_sca = 0.1 eps = 1.0 hs_radii = 0.05 * np.random.randn(nparticles) + 1 volpart = np.sum(4. / 3. * np.pi * hs_radii**3) phi = 0.7 boxl = (volpart / phi)**(1 / 3.) boxv = [boxl, boxl, boxl] coords = np.random.rand(nparticles * 3) * boxl ncellx_scale = get_ncellsx_scale(np.ones(nparticles), boxv) bdim = 3 distance_method = Distance.PERIODIC pot_cellists = HS_WCA(use_cell_lists=True, eps=eps, sca=pot_sca, radii=hs_radii * radius_sca, boxvec=boxv, ndim=bdim, ncellx_scale=ncellx_scale, distance_method=distance_method) pot_no_cellists = HS_WCA(use_cell_lists=False, eps=eps, sca=pot_sca, radii=hs_radii * radius_sca, boxvec=boxv, ndim=bdim, ncellx_scale=ncellx_scale, distance_method=distance_method) nsteps = 1000 tol = 1e-5 res_cell_lists = lbfgs_cpp(coords, pot_cellists, nsteps=nsteps, tol=tol) res_no_cell_lists = lbfgs_cpp(coords, pot_no_cellists, nsteps=nsteps, tol=tol) fcoords_cell_lists = res_cell_lists.coords fcoords_no_cell_lists = res_no_cell_lists.coords # self.assertEqual(fcoords_no_cell_lists,fcoords_cell_lists) self.assertTrue(np.all(fcoords_no_cell_lists == fcoords_cell_lists))
def map_binary_inversepower( foldername, particle_coords, optimizer, parameter_dict, random_coord_0=0, random_coord_1=-1, z=0, ): """ Finds whether a point defined by particle_coord on the meshgrid correspond to a minimum or not for a 2d case. """ foldpath = BASE_DIRECTORY + "/" + foldername # import params sysparams = load_params(foldpath) (hs_radii, initial_coords, box_length) = load_secondary_params(foldpath) assert sysparams.ndim.value == 2 minimum_coords = np.loadtxt(foldpath + "/coords_of_minimum.txt", delimiter=",") quench_coords = initial_coords.copy() if len(quench_coords) == 16: quench_coords = ( quench_coords + particle_coords[0] * VEC_8_0 + particle_coords[1] * VEC_8_1 + z * VEC_8_2 ) elif len(quench_coords) == 32: quench_coords = ( quench_coords + particle_coords[0] * VEC_16_0 + particle_coords[1] * VEC_16_1 + z * VEC_16_2 ) elif len(quench_coords) == 64: quench_coords = ( quench_coords + particle_coords[0] * VEC_16_0 + particle_coords[1] * VEC_16_1 + z * VEC_16_2 ) else: raise Exception("error other random coords have not been generated") print(quench_coords, "quench") # print(quench_coords, 'quench coords') # box length box_length = float(box_length) boxv = [box_length] * sysparams.ndim.value ncellx_scale = get_ncellsx_scale(hs_radii, boxv) potential = InversePower( sysparams.power.value, sysparams.eps.value, use_cell_lists=False, ndim=sysparams.ndim.value, radii=hs_radii * 1.0, boxvec=boxv, ) # ret = quench_mixed_optimizer(potential, # quench_coords, # make sure right coords are being passed # T=10, # step=1, # nsteps=100000, # conv_tol=1e-8, # tol=1e-6, rtol=1e-4, atol=1e-4) # ret = quench_steepest( # potential, # quench_coords, # make sure right coords are being passed # nsteps=2000000, # stepsize=5e-3, # for steepest descent step size should be small # tol=1e-4) # ret = quench_cvode_opt(potential, quench_coords, tol=1e-6, rtol=1e-4, atol=1e-4) try: ret = optimizer(quench_coords, potential, **parameter_dict) except: print(quench_coords, "failed here") print(initial_coords, "coords") print(len(quench_coords)) raise Exception("failure") # ret = lbfgs_cpp(quench_coords, potential, tol=1e-8, M=1) # This exists because some runs don't have hessian evaluations try: ret["nhev"] except: ret["nhev"] = 0 coordarg = 0 results = (ret.coords, ret.success, coordarg, ret.nfev, ret.nsteps, ret.nhev) # the reason the potential is being passed is because quench coords needs the potential to figure out what to do return results
def map_binary_inversepower( foldername, particle_coords, optimizer, parameter_dict, random_coord_0=0, random_coord_1=-1, z=0, index=None, mesh_length=None, ): """ Finds whether a point defined by particle_coord on the meshgrid correspond to a minimum or not for a 2d case. """ foldpath = BASE_DIRECTORY + "/" + foldername # import params sysparams = load_params(foldpath) (hs_radii, initial_coords, box_length) = load_secondary_params(foldpath) assert sysparams.ndim.value == 2 quench_coords = initial_coords.copy() print("initial_coords", initial_coords) print(particle_coords[0], particle_coords[1], "vector coefficients as passed") print("z value") quench_coords = (quench_coords + particle_coords[0] * VEC_16_0 + particle_coords[1] * VEC_16_1 + z * VEC_16_2) # TODO: save this as a unit meshgrid # print(quench_coords, 'quench coords') # box length box_length = float(box_length) boxv = [box_length] * sysparams.ndim.value ncellx_scale = get_ncellsx_scale(hs_radii, boxv) print(hs_radii) potential = InversePower( sysparams.power.value, sysparams.eps.value, use_cell_lists=False, ndim=sysparams.ndim.value, radii=hs_radii * 1.0, boxvec=boxv, ) # save potential parameters # writing this out since Enum to dict conversion does not give the mapping we want potential_params_fname = "potential_params.yaml" potential_param_dict = { "ndim": sysparams.ndim.value, "phi": sysparams.phi.value, "seed": 0, "n_part": sysparams.n_part.value, "r1": sysparams.r1.value, "r2": sysparams.r2.value, "rstd1": sysparams.rstd1.value, "rstd2": sysparams.rstd2.value, "use_cell_lists": int(False), "power": sysparams.power.value, "eps": sysparams.eps.value, } param_str = generate_param_str_from_dict(potential_param_dict) # make directory to emulate structure by refactored code emulation_folder = COMPARE_FOLDER_NAME + "/" + param_str # add README to emulation folder os.makedirs(emulation_folder, exist_ok=True) with open(COMPARE_FOLDER_NAME + "/README.org", "w") as f: f.write(" \#+AUTHOR Praharsh Suryadevara .\n") f.write("* Read First.") f.write( "This dirctory has been auto-generated by old code before refactoring. Do not change.\n" ) # emulates path of the refactored code ensemble_folder_path = emulation_folder + "/ensemble/random_plane" os.makedirs(ensemble_folder_path, exist_ok=True) # 0 to emulate the addition of seed sec_param_folder_path = emulation_folder + "/sec_params/0" os.makedirs(sec_param_folder_path, exist_ok=True) old_code_results_folder_path = emulation_folder + "/old_data" os.makedirs(old_code_results_folder_path, exist_ok=True) with open(emulation_folder + "/params.yaml", "w") as param_file: yaml.dump(potential_param_dict, param_file) opt_param_fname = "minima_finder_params.yaml" with open(emulation_folder + "/" + opt_param_fname, "w") as param_file: yaml.dump(parameter_dict, param_file) initial_coords_fname = str(index) + ".txt" np.savetxt(ensemble_folder_path + "/" + initial_coords_fname, quench_coords, delimiter=",") mesh_coords_fname = str(index) + "_mesh.txt" np.savetxt(ensemble_folder_path + "/" + mesh_coords_fname, particle_coords, delimiter=",") if mesh_length is not None: # 2 *[particle_coords[0], particle_coords[1]]/mesh_length -0.5 form our unit mesh_grid # centered around [0, 0] mesh_coords = (2 * np.array([particle_coords[0], particle_coords[1]]) / mesh_length - 0.5) mesh_coords_fname = str(index) + "_mesh.txt" np.savetxt(ensemble_folder_path + "/" + mesh_coords_fname, mesh_coords, delimiter=",") np.savetxt( sec_param_folder_path + "/" + "initial_coords.txt", initial_coords, delimiter=",", ) np.savetxt( sec_param_folder_path + "/" + "box_length.txt", np.array([box_length]), delimiter=",", ) np.savetxt(sec_param_folder_path + "/" + "hs_radii.txt", hs_radii, delimiter=",") # ret = quench_mixed_optimizer(potential, # quench_coords, # make sure right coords are being passed # T=10, # step=1, # nsteps=100000, # conv_tol=1e-8, # tol=1e-6, rtol=1e-4, atol=1e-4) # ret = quench_steepest( # potential, # quench_coords, # make sure right coords are being passed # nsteps=2000000, # stepsize=5e-3, # for steepest descent step size should be small # tol=1e-4) # ret = quench_cvode_opt(potential, quench_coords, tol=1e-6, rtol=1e-4, atol=1e-4) try: ret = optimizer(quench_coords, potential, **parameter_dict) except: raise Exception("failure") # ret = lbfgs_cpp(quench_coords, potential, tol=1e-8, M=1) # This exists because some runs don't have hessian evaluations try: ret["nhev"] except: ret["nhev"] = 0 coordarg = 0 final_coords = ret["coords"] final_coords_fname = str(index) + "_coords.txt" np.savetxt( old_code_results_folder_path + "/" + final_coords_fname, final_coords, delimiter=",", ) energy, grad, hess = potential.getEnergyGradientHessian(final_coords) hessian_fname = str(index) + "_hessian.txt" np.savetxt(old_code_results_folder_path + "/" + hessian_fname, hess, delimiter=",") grad_fname = str(index) + "_grad.txt" np.savetxt(old_code_results_folder_path + "/" + grad_fname, grad, delimiter=",") last_step_fname = str(index) + "_step.txt" # np.savetxt(old_code_results_folder_path + '/' + # last_step_fname, ret['step'], delimiter=',') # check that the minimum hessian eigenvalue is positive # print out the eigenvector corresponding to it eigvals, eigvecs = np.linalg.eigh(hess) print(eigvals[1]) print(eigvecs[:, 1]) # step_in_eigvec_basis = np.matmul(eigvecs.T, ret['step']) # step_in_eigvec_basis_normalized = step_in_eigvec_basis/np.linalg.norm(step_in_eigvec_basis) # -1e-15 is to avoid numerical issues if np.min(eigvals) < -1e-3: print("minimum Eigenvalue: ", np.min(eigvals)) print("Eigenvalues: ", eigvals) raise Exception("negative eigenvalue") # save heuristics as a dict results = ( ret.coords, ret.success, coordarg, ret.nfev, ret.nsteps, ret.nhev, eigvecs, ) # simplified dictionary since we're only using the success variable res_dict = { "success": bool(ret.success), "nsteps": ret.nsteps, "energy": ret.energy, "nfev": ret.nfev, } # print("-------------------------------------------------steppp", step_in_eigvec_basis_normalized) # print("eigenvalues", eigvals) yaml_fname = str(index) + ".yaml" # save heuristics as yaml with open(old_code_results_folder_path + "/" + yaml_fname, "w") as f: yaml.dump(res_dict, f) print(ret.nsteps, "nsteps") # the reason the potential is being passed is because quench coords needs the potential to figure out what to do return results