def test_chunks(self): full_len = 10 chunk_len = 3 chunk_n = 2 # Generate a few random structures elrnd = ['H', 'C', 'O', 'N'] asernd = [] for n in range(full_len): aselen = np.random.randint(1, 10) asernd.append( Atoms(symbols=np.random.choice(elrnd, aselen), positions=np.random.random((aselen, 3)))) testcoll = AtomsCollection(asernd) # Test with size chunks = testcoll.chunkify(chunk_size=chunk_len) self.assertEqual(len(chunks), np.ceil(full_len / (1.0 * chunk_len))) self.assertEqual(chunks[-1].length, full_len % chunk_len) # Test with number chunks = testcoll.chunkify(chunk_n=chunk_n) self.assertEqual(len(chunks), chunk_n)
def test_loadarray(self): g0 = Gene('latt_abc_len', 1.0, {}) c1 = AtomsCollection([Atoms('C'), Atoms('C')]) c1.set_array('latt_abc_len', [1, 2]) p1 = PhylogenCluster(c1, []) p1.set_genes([g0], load_arrays=True) self.assertTrue(np.all(p1.get_genome_vectors()[0] == [[1], [2]]))
def test_loadres(self): # Load some test files and check if regular loading works reslist = glob.glob( os.path.join(_TESTDATA_DIR, 'rescollection', '*.res')) testcoll = AtomsCollection(reslist) self.assertEqual(testcoll.length, len(reslist)) # Now try the same, but with single atoms objects aselist = [io.read(str(fname)) for fname in reslist] testcoll = AtomsCollection(aselist) self.assertEqual(testcoll.length, len(reslist))
def test_tree(self): aselist = [Atoms('C'), Atoms('H'), Atoms('N'), Atoms('O')] testcoll = AtomsCollection(aselist) testcoll.save_tree('test_save', 'xyz', safety_check=2) loadcoll = AtomsCollection.load_tree('test_save', 'xyz') self.assertTrue(''.join(loadcoll.all.get_chemical_formula()) == 'CHNO') # Try a custom save format def custom_save(a, path, format_string): with open(os.path.join(path, 'struct.custom'), 'w') as f: f.write(format_string.format(''.join( a.get_chemical_formula()))) def custom_load(path, marker): with open(os.path.join(path, 'struct.custom')) as f: l = f.read().strip() return Atoms(l.split(marker)[1].strip()) testcoll.save_tree('test_save', custom_save, opt_args={'format_string': 'Formula:{0}'}, safety_check=2) loadcoll = AtomsCollection.load_tree('test_save', custom_load, opt_args={'marker': ':'}) self.assertTrue(''.join(loadcoll.all.get_chemical_formula()) == 'CHNO')
def test_airss(self): to_gen = 10 # Load the Al.cell file (capture the annoying ASE output...) _stdout, sys.stdout = sys.stdout, StringIO() agen = airssGen(os.path.join(_TESTDATA_DIR, 'Al.cell'), n=to_gen) try: acoll = AtomsCollection(agen) except RuntimeError as e: if 'Buildcell' in str(e): sys.stdout = _stdout # Then we just don't have the program print('WARNING - The AIRSS generator could not be tested as ' 'no AIRSS installation has been found on this system.') return else: raise e sys.stdout = _stdout # Some basic checks self.assertEqual(acoll.length, to_gen) self.assertTrue( all([chem == 'Al8' for chem in acoll.all.get_chemical_formula()]))
def load_muairss_collection(struct, params, batch_path=''): # Output folder out_path = os.path.join(batch_path, params['out_folder']) load_formats = { 'dftb+': dftb_read_input, 'castep': castep_read_input, 'uep': uep_read_input } calcs = [s.strip().lower() for s in params['calculator'].split(',')] if 'all' in calcs: calcs = load_formats.keys() loaded = {} for cname in calcs: opt_args = {} if cname == 'uep': opt_args['atoms'] = struct calc_path = os.path.join(out_path, cname) dc = AtomsCollection.load_tree(calc_path, load_formats[cname], opt_args=opt_args, safety_check=2) loaded[cname] = dc return loaded
def test_cluster(self): a1 = Atoms(cell=[1, 1, 1], info={'name': 'a1'}) a2 = Atoms(cell=[1, 1, 2], info={'name': 'a2'}) a3 = Atoms(cell=[3, 3, 3], info={'name': 'a3'}) c1 = AtomsCollection([a1, a2, a3]) p1 = PhylogenCluster(c1, [Gene('latt_abc_len', 1.0, {})]) clinds, clslice = p1.get_hier_clusters(0.5, method='complete') getname = lambda a: a.info['name'] cnames = [sorted(c1[sl].all.map(getname)) for sl in clslice] cnames.sort(key=lambda x: len(x)) self.assertTrue(cnames == [['a3'], ['a1', 'a2']]) # Retry with k-means clustc = p1.get_kmeans_clusters(2) cnames = [sorted(c1[sl].all.map(getname)) for sl in clslice] cnames.sort(key=lambda x: len(x)) self.assertTrue(cnames == [['a3'], ['a1', 'a2']])
def test_diprotavg(self): # Test dipolar rotational averaging eth = io.read(os.path.join(_TESTDATA_DIR, 'ethanol.magres')) from ase.quaternions import Quaternion from soprano.properties.transform import Rotate from soprano.collection import AtomsCollection from soprano.collection.generate import transformGen from soprano.properties.nmr import DipolarTensor N = 30 # Number of averaging steps axis = np.array([1.0, 1.0, 0]) axis /= np.linalg.norm(axis) rot = Rotate(quaternion=Quaternion.from_axis_angle( axis, 2*np.pi/N)) rot_eth = AtomsCollection(transformGen(eth, rot, N)) rot_dip = [D[(0, 1)] for D in DipolarTensor.get(rot_eth, sel_i=[0], sel_j=[1])] dip_avg_num = np.average(rot_dip, axis=0) dip_tens = NMRTensor.make_dipolar(eth, 0, 1, rotation_axis=axis) dip_avg_tens = dip_tens.data self.assertTrue(np.allclose(dip_avg_num, dip_avg_tens)) # Test eigenvectors evecs = dip_tens.eigenvectors self.assertTrue(np.allclose(np.dot(evecs.T, evecs), np.eye(3)))
def generate_muairss_collection(struct, params): if params["mu_symbol"] in struct.get_chemical_symbols(): print( "WARNING: chosen muon symbol conflicts with existing elements in" " the starting unit cell. This could cause mistakes" ) # Make a supercell sm = make_3x3(params["supercell"]) # ASE's make_supercell is weird, avoid if not necessary... smdiag = np.diag(sm).astype(int) if np.all(np.diag(smdiag) == sm): scell0 = struct.repeat(smdiag) else: scell0 = make_supercell(struct, sm) reduced_struct = find_primitive_structure(struct) print("Generating defect configurations...") # Seed the random generator Random.reseed(params["random_seed"]) # Now generate the defect configurations defect_gen = defectGen( reduced_struct, "H", poisson_r=params["poisson_r"], vdw_scale=params["vdw_scale"], ) defect_collection = AtomsCollection(defect_gen) print("{0} configurations generated".format(len(defect_collection))) collection = [] for atoms in defect_collection: # Where's the muon? # We rely on the fact that it's always put at the first place mupos = atoms.get_positions()[0] scell = scell0.copy() + Atoms( "H", positions=[mupos], masses=[constants.m_mu_amu] ) # Add castep custom species csp = scell0.get_chemical_symbols() + [params["mu_symbol"]] scell.set_array("castep_custom_species", np.array(csp)) scell.set_pbc(params["dftb_pbc"]) collection.append(scell) return AtomsCollection(collection)
def test_propertymap(self): from soprano.properties.basic import NumAtoms num_atoms = np.random.randint(1, 11, size=10) coll = AtomsCollection([Atoms('H'*n) for n in num_atoms]) num_atoms_prop = coll.all.map(NumAtoms.get) self.assertTrue((num_atoms == num_atoms_prop).all)
def test_linspace(self): a1 = Atoms('CO', [[0.0, 0.0, 0.0], [0.0, 0.2, 0.0]], cell=[1] * 3) a2 = Atoms('CO', [[0.0, 0.0, 0.0], [0.0, 0.8, 0.0]], cell=[1] * 3) lgen = linspaceGen(a1, a2, steps=5, periodic=False) lcoll = AtomsCollection(lgen) self.assertTrue( np.all( np.isclose(lcoll.all.get_positions()[:, 1, 1], np.linspace(0.2, 0.8, 5)))) # With periodicity lgen = linspaceGen(a1, a2, steps=5, periodic=True) lcoll = AtomsCollection(lgen) self.assertTrue( np.all( np.isclose(lcoll.all.get_positions()[:, 1, 1], np.linspace(0.2, -0.2, 5))))
def test_mapsel(self): from soprano.collection import AtomsCollection rand_el = ['H' if x > 0.5 else 'C' for x in np.random.random(10)] coll = AtomsCollection([Atoms(el) for el in rand_el]) h_sel = coll.all.map(AtomSelection.from_element, element='H') self.assertTrue(all([len(s) == 1 if rand_el[i] == 'H' else len(s) == 0 for i, s in enumerate(h_sel)]))
def test_gene(self): c1 = AtomsCollection([ Atoms('CCC', positions=[[0, 0, 0], [0.2, 0, 0], [0.85, 0, 0]], cell=[1] * 3) ]) g1 = Gene('linkage_list', 1.0, {'size': 3}) p1 = PhylogenCluster(c1, [g1]) graw = p1.get_genome_vectors() self.assertTrue(np.allclose(graw[0], [0.15, 0.2, 0.35]))
def test_save(self): # Test saving and loading collection testcoll = AtomsCollection([Atoms('H')]) testcoll.set_array('test', np.array([2])) outf = os.path.join(_TEST_DIR, 'collection.pkl') testcoll.save(outf) # Reload testcoll = AtomsCollection.load(outf) self.assertEqual(testcoll.get_array('test')[0], 2) os.remove(outf)
def test_calculator(self): from ase.calculators.test import TestPotential from ase.calculators.lj import LennardJones # Generate a few random structures elrnd = ['H', 'C', 'O', 'N'] asernd = [] for n in range(4): aselen = np.random.randint(2, 10) asernd.append( Atoms(symbols=np.random.choice(elrnd, aselen), positions=np.random.random((aselen, 3)))) testcoll = AtomsCollection(asernd) testcoll.set_calculators(LennardJones, labels=['a', 'b', 'c', 'd'], params={'epsilon': 1.2}) testcoll.run_calculators() def extract_nrg(s): return s.calc.results['energy'] energies = np.array(testcoll.all.map(extract_nrg)) self.assertTrue(not np.isnan(energies).any())
def test_dummyprop(self): # Define a dummy derived property and test it class DummyProperty(AtomsProperty): default_name = 'dummy' default_params = {'mul': 2.0} @staticmethod def extract(s, mul): return s.positions.shape[0] * mul # Now two atoms objects to test it on a1 = Atoms('C') a2 = Atoms('CC') dummyDoubled = DummyProperty(name='doubledummy', mul=4) self.assertEqual(DummyProperty.get(a1), 2.0) self.assertEqual(dummyDoubled(a2), 8.0) # Also check that improper parameters are rejected self.assertRaises(ValueError, DummyProperty, wrong='this is wrong') # Test behaviour on a collection instead c1 = AtomsCollection([a1, a2]) c2 = AtomsCollection([a2, a1]) DummyProperty.get(c1, store_array=True) dummyDoubled(c2, store_array=True) self.assertTrue(np.all(c1.get_array('dummy') == [2, 4])) self.assertTrue(np.all(c2.get_array('doubledummy') == [8, 4]))
def test_slices(self): aselist = [Atoms('C'), Atoms('C'), Atoms('H'), Atoms('C')] testcoll = AtomsCollection(aselist) coll_h = testcoll[2] coll_c = testcoll[(0, 1, 3)] self.assertTrue( all([f == 'H' for f in coll_h.all.get_chemical_formula()])) self.assertTrue( all([f == 'C' for f in coll_c.all.get_chemical_formula()]))
def generate_muairss_collection(struct, params): if params['mu_symbol'] in struct.get_chemical_symbols(): print('WARNING: chosen muon symbol conflicts with existing elements in' ' the starting unit cell. This could cause mistakes') # Make a supercell sm = make_3x3(params['supercell']) # ASE's make_supercell is weird, avoid if not necessary... smdiag = np.diag(sm).astype(int) if np.all(np.diag(smdiag) == sm): scell0 = struct.repeat(smdiag) else: scell0 = make_supercell(struct, sm) reduced_struct = find_primitive_structure(struct) print('Generating defect configurations...') # Now generate the defect configurations defect_gen = defectGen(reduced_struct, 'H', poisson_r=params['poisson_r'], vdw_scale=params['vdw_scale']) defect_collection = AtomsCollection(defect_gen) print('{0} configurations generated'.format(len(defect_collection))) collection = [] for atoms in defect_collection: # Where's the muon? # We rely on the fact that it's always put at the first place mupos = atoms.get_positions()[0] scell = scell0.copy() + Atoms('H', positions=[mupos]) # Add castep custom species csp = scell0.get_chemical_symbols() + [params['mu_symbol']] scell.set_array('castep_custom_species', np.array(csp)) scell.set_pbc(params['dftb_pbc']) collection.append(scell) return AtomsCollection(collection)
def test_customgene(self): c1 = AtomsCollection( [Atoms('C', positions=[[i / 5.0, 0, 0]]) for i in range(5)]) # First, check failure self.assertRaises(RuntimeError, Gene, 'first_x_coord') # Then actual success def first_x_parser(c): return np.array(c.all.get_positions())[:, 0, 0] g1 = Gene('first_x_coord', parser=first_x_parser) self.assertTrue(np.all(g1.evaluate(c1) == [i / 5.0 for i in range(5)]))
def test_loadgene(self): gfpath = os.path.join(_TESTDATA_DIR, 'testfile.gene') g0 = Gene('latt_abc_len', 1.0, {}) g1 = Gene('linkage_list', 0.5, {'size': 3}) glist = load_genefile(gfpath) self.assertEqual(glist[0], g0) self.assertEqual(glist[1], g1) # Now test that it works also when instantiating a cluster c1 = AtomsCollection( [Atoms('CCC', positions=np.random.random((3, 3)), cell=[1] * 3)]) p1 = PhylogenCluster(c1, gfpath)
def test_arrays(self): # Generate a few random structures elrnd = ['H', 'C', 'O', 'N'] asernd = [] for n in range(4): aselen = np.random.randint(1, 10) asernd.append( Atoms(symbols=np.random.choice(elrnd, aselen), positions=np.random.random((aselen, 3)))) testcoll = AtomsCollection(asernd) # Now try assigning some arrays arr = np.arange(testcoll.length) testcoll.set_array('testarr', arr, shape=(1, )) testcoll.set_array('testarr_2', list(zip(arr, arr)), shape=(2, )) testcoll.set_array('testarr_func', lambda a: len(a.get_positions()), shape=(1, )) self.assertTrue(np.all(testcoll.get_array('testarr') == arr))
def test_rattle(self): a = Atoms('CO', [[0.0, 0.0, 0.0], [0.0, 0.5, 0.0]]) pos = a.get_positions() # Some exception tests wronggen = rattleGen(a, [3, 4, 5]) self.assertRaises(ValueError, next, wronggen) wronggen = rattleGen(a, [[1, 2], [4, 5]]) self.assertRaises(ValueError, next, wronggen) rgen = rattleGen(a, [[0.01, 0, 0], [0, 0.02, 0]]) rcoll = AtomsCollection(rgen) rpos = rcoll.all.get_positions() self.assertTrue(np.all(np.abs((rpos - pos)[:, 0, 0]) <= 0.01)) self.assertTrue(np.all(np.abs((rpos - pos)[:, 1, 1]) <= 0.02))
def test_defect(self): si2 = bulk('Si') poisson_r = 0.5 dGen = defectGen(si2, 'H', poisson_r) dColl = AtomsCollection(dGen) dPos = dColl.all.get_positions()[:, 0] holds = True for i, p1 in enumerate(dPos[:-1]): vecs, _ = minimum_periodic(dPos[i + 1:] - p1, si2.get_cell()) p_holds = (np.linalg.norm(vecs, axis=1) >= poisson_r).all() holds = holds and p_holds self.assertTrue(holds)
def test_coordhist(self): ala = ase.io.read(os.path.join(_TESTDATA_DIR, 'mol_crystal.cif')) nh3 = ase.io.read(os.path.join(_TESTDATA_DIR, 'nh3.cif')) c = AtomsCollection([ala, nh3]) g = Gene('coord_histogram') h = g.evaluate(c) self.assertTrue((h[0] == [0, 4, 0, 4, 0, 0, 0]).all()) self.assertTrue((h[1] == 0).all()) # No C at all in this one # Now for something different... g = Gene('coord_histogram', params={'s1': 'N'}) h = g.evaluate(c) self.assertTrue((h[0] == [0, 0, 0, 4, 0, 0, 0]).all()) # 4 NH3 groups self.assertTrue((h[1] == [0, 0, 0, 1, 0, 0, 0]).all())
def test_sum(self): # Generate a few random structures elrnd = ['H', 'C', 'O', 'N'] asernd = [] for n in range(4): aselen = np.random.randint(1, 10) asernd.append( Atoms(symbols=np.random.choice(elrnd, aselen), positions=np.random.random((aselen, 3)))) testcoll1 = AtomsCollection(asernd[:2]) testcoll2 = AtomsCollection(asernd[2:]) testcoll1.set_array('joint', ['t', 'e']) testcoll2.set_array('joint', ['s', 't']) testcoll = testcoll1 testcoll += testcoll2 self.assertTrue(''.join(testcoll.get_array('joint')) == 'test')
def load_muairss_collection(struct, params, batch_path=""): # Output folder out_path = os.path.join(batch_path, params["out_folder"]) io_formats = { "castep": ReadWriteCastep, "dftb+": ReadWriteDFTB, "uep": ReadWriteUEP, } calcs = [s.strip().lower() for s in params["calculator"].split(",")] if "all" in calcs: calcs = io_formats.keys() loaded = {} for cname in calcs: rw = io_formats[cname](params) calc_path = os.path.join(out_path, cname) dc = AtomsCollection.load_tree( calc_path, rw.read, safety_check=2, tolerant=True ) alln = len(glob.glob(calc_path + "/*")) total_structures = len(dc.structures) if total_structures == 0: return elif total_structures / alln < 0.9: print( """If more than 10% of structures could not be loaded, we advise adjusting the parameters and re-running the {0} optimisation for the structures that failed.""".format( cname ) ) loaded[cname] = dc return loaded
def test_sorting(self): # Generate a few structures struct_n = 5 aselist = [] for n in range(struct_n): aselist.append(Atoms()) testcoll = AtomsCollection(aselist) testcoll.set_array('sorter', np.array(range(struct_n, 0, -1))) testcoll.set_array('sorted', np.array(range(1, struct_n + 1))) testcoll = testcoll.sorted_byarray('sorter') self.assertTrue( np.all(testcoll.get_array('sorted') == range(struct_n, 0, -1)))
def load_muairss_collection(struct, params, batch_path=''): # Output folder out_path = os.path.join(batch_path, params['out_folder']) io_formats = { 'castep': ReadWriteCastep, 'dftb+': ReadWriteDFTB, 'uep': ReadWriteUEP } calcs = [s.strip().lower() for s in params['calculator'].split(',')] if 'all' in calcs: calcs = io_formats.keys() loaded = {} for cname in calcs: rw = io_formats[cname](params) calc_path = os.path.join(out_path, cname) dc = AtomsCollection.load_tree(calc_path, rw.read, safety_check=2, tolerant=True) print("If more than 10% of structures could not be loaded, \ we advise adjusting the parameters and re-running the {0} \ optimisation for the structures that failed.".format(cname)) total_structures = len(dc.structures) if total_structures == 0: return loaded[cname] = dc return loaded
def muon_vibrational_average_write(structure, method="independent", mu_index=-1, mu_symbol="H:mu", grid_n=20, sigma_n=3, avgprop="hyperfine", calculator="castep", displace_T=0, phonon_source_file=None, phonon_source_type="castep", **kwargs): """ Write input files to compute a vibrational average for a quantity on a muon in a given system. | Pars: | structure (str): Filename for input structure file | method (str): Method to use for the average. Options are | 'independent', 'montecarlo'. | Default is 'independent'. | mu_index (int): Position of the muon in the given cell file. | Default is -1. | mu_symbol (str): Use this symbol to look for the muon among | CASTEP custom species. Overrides muon_index if | present in cell. | grid_n (int): Number of configurations used for sampling. | Applies slightly | differently to different schemes. | sigma_n (int): Number of sigmas of the harmonic wavefunction used | for sampling. | avgprop (str): Property to calculate and average. Default is | 'hyperfine'. | calculator (str): Source of the property to calculate and average. | Can be 'castep' or 'dftb+'. Default is 'castep'. | phonon_source (str):Source of the phonon data. Can be 'castep' or | 'asedftbp'. Default is 'castep'. | **kwargs: Other arguments (such as specific arguments for | the given phonon method) """ # Open the structure file with silence_stdio(): cell = io.read(structure) path = os.path.split(structure)[0] sname = seedname(structure) cell.info["name"] = sname # Fetch species try: species = cell.get_array("castep_custom_species") except KeyError: species = np.array(cell.get_chemical_symbols()) mu_indices = np.where(species == mu_symbol)[0] if len(mu_indices) > 1: raise MuonAverageError("More than one muon found in the system") elif len(mu_indices) == 1: mu_index = mu_indices[0] else: species = list(species) species[mu_index] = mu_symbol species = np.array(species) cell.set_array("castep_custom_species", species) io_formats = {"castep": ReadWriteCastep, "dftb+": ReadWriteDFTB} # Load the phonons if phonon_source_file is not None: phpath, phfile = os.path.split(phonon_source_file) phfile = seedname(seedname(phfile)) # have to do twice for dftb case else: phpath = path phfile = sname try: rw = io_formats[phonon_source_type]() atoms = rw.read(phpath, phfile, read_phonons=True) ph_evals = atoms.info["ph_evals"] ph_evecs = atoms.info["ph_evecs"] except IOError: raise return except KeyError: phonon_source_file = os.path.join(phpath, phfile + ".phonon") if phonon_source_type == "dftb+": phonon_source_file = phonon_source_file + "s.pkl" raise (IOError( "Phonon file {0} could not be read.".format(phonon_source_file))) return # Fetch masses try: masses = parse_castep_masses(cell) except AttributeError: # Just fall back on ASE standard masses if not available masses = cell.get_masses() masses[mu_index] = constants.m_mu_amu cell.set_masses(masses) # Now create the distribution scheme if method == "independent": displsch = IndependentDisplacements(ph_evals, ph_evecs, masses, mu_index, sigma_n) elif method == "montecarlo": # Set seed np.random.seed(kwargs["random_seed"]) displsch = MonteCarloDisplacements(ph_evals, ph_evecs, masses) displsch.recalc_displacements(n=grid_n, T=displace_T) # Make it a collection pos = cell.get_positions() displaced_cells = [] for i, d in enumerate(displsch.displacements): dcell = cell.copy() dcell.set_positions(pos + d) if calculator == "dftb" and not kwargs["dftb_pbc"]: dcell.set_pbc(False) dcell.info["name"] = sname + "_displaced_{0}".format(i) displaced_cells.append(dcell) if kwargs["write_allconf"]: # Write a global configuration structure allconf = sum(displaced_cells, cell.copy()) with silence_stdio(): if all(allconf.get_pbc()): io.write(sname + "_allconf.cell", allconf) else: io.write(sname + "_allconf.xyz", allconf) # Get a calculator if calculator == "castep": params = { "castep_param": kwargs["castep_param"], "k_points_grid": kwargs["k_points_grid"], "mu_symbol": mu_symbol, } io_format = ReadWriteCastep(params=params, calc=cell.calc, script=kwargs["script_file"]) opt_args = {"calc_type": "MAGRES"} elif calculator == "dftb+": params = { "dftb_set": kwargs["dftb_set"], "dftb_pbc": kwargs["dftb_pbc"], "k_points_grid": kwargs["k_points_grid"] if kwargs["dftb_pbc"] else None, } io_format = ReadWriteDFTB(params=params, calc=cell.calc, script=kwargs["script_file"]) opt_args = {"calc_type": "SPINPOL"} displaced_coll = AtomsCollection(displaced_cells) displaced_coll.info["displacement_scheme"] = displsch displaced_coll.info["muon_index"] = mu_index displaced_coll.save_tree(sname + "_displaced", io_format.write, opt_args=opt_args)
parser.add_argument('-corrmat_minforce', type=float, default=0.01, help="Correlation matrix minimum force") parser.add_argument('-corrmat_maxforce', type=float, default=1.0, help="Correlation matrix maximum force") parser.add_argument('-savepkl', type=str, default=None, help="Directory to save collection as pickle file") args = parser.parse_args() # First, parse the gene list gene_list = load_genefile(args.seedname + '.gene') # Then create an AtomsCollection if not args.pkl: aC = AtomsCollection(args.input_files, info={'name': args.seedname}, cell_reduce=True, progress=True) else: aC = AtomsCollection([]) for f in args.input_files: aC += AtomsCollection.load(f) # Take only n lowest energies if required if (args.n is not None): # Sort by energy CalcEnergy.get(aC, store_array=True) aC = aC.sorted_byarray('calc_energy')[:args.n] #discard_Z = args.Z is not None # Calculate genomes