Example #1
0
def check_relax_ML_dist():
    g0 = ase_read("POSCAR")
    g1 = ase_read("run.final/CONTCAR")

    # Compute layer thickness
    t0 = max(g0.positions[:,2]) - min(g0.positions[:,2])
    t1 = max(g1.positions[:,2]) - min(g1.positions[:,2])

    # Compute distance between ML
    d0 = g0.cell[2,2] - t0
    d1 = g1.cell[2,2] - t1

    print("d0=%.3f Ang" % d0, "d1=%.3f Ang" % d1)
    print("Diff=%5.2g Ang reldiff=%5.2g%%" % (d0-d1, 100*(d0-d1)/d0))

    return d0, d1
def Minimisation_Function(cluster, collection, cluster_name):
    #######################################################################################
    cluster.pbc = True  # make sure that the periodic boundry conditions are set off
    #######################################################################################
    # Perform the local optimisation method on the cluster.
    original_path = os.getcwd()
    offspring_name = str(cluster_name)
    clusters_to_make_name = 'clusters_for_VASP'
    if not os.path.exists(clusters_to_make_name):
        os.makedir(clusters_to_make_name)
    copyfile('VASP_Files/INCAR',
             clusters_to_make_name + '/' + offspring_name + '/INCAR')
    copyfile('VASP_Files/POTCAR',
             clusters_to_make_name + '/' + offspring_name + '/POTCAR')
    copyfile('VASP_Files/KPOINTS',
             clusters_to_make_name + '/' + offspring_name + '/KPOINTS')
    os.chdir(clusters_to_make_name + '/' + offspring_name)
    ase_write(cluster, 'POSCAR', 'vasp')
    startTime = time.time()
    try:
        Popen(['srun', 'vasp'])
    except Exception:
        pass
    endTime = time.time()
    cluster = ase_read('OUTCAR')
    os.chdir(original_path)
    ####################################################################################################################
    # Write information about the algorithm
    Info = {}
    Info["INFO.txt"] = ''
    #Info["INFO.txt"] += ("No of Force Calls: " + str(dyn.get_number_of_steps()) + '\n')
    Info["INFO.txt"] += ("Time (s): " + str(endTime - startTime) + '\n')
    #Info["INFO.txt"] += ("Cluster converged?: " + str(dyn.converged()) + '\n')
    ####################################################################################################################
    return cluster, converged, Info
Example #3
0
def read_chrg(genfname='geoinp.gen', chrg_fname='charges.dat', hsdfname='dftb_in.hsd', ):
    '''
    Prerequisites: 
        * charges.dat to be read;  
        * correspondence ``.gen``  
        * input ``dftb_in.hsd`` 
    Intermediates:
        max_orbital_dict: { 'Au':'d', O:'p', ... }
    '''
    # read chem_symbol:max_orbital from HSD input
    hsd = HSD(hsdfname)
    max_orbital_dict = hsd.get_nestkeys()['Hamiltonian']['MaxAngularMomentum'] 
    # read chem_symbol list from .gen file
    atoms = ase_read(filename=genfname, format='gen')
    chemsymbol_list = atoms.get_chemical_symbols()
    # read charges.dat  
    with open(chrg_fname, 'r') as chrgf:
        # read header and transform strings into proper type 
        headline = chrgf.readline()
        version, t_blockcharges, t_imaginaryblock, nspin, checksum = headline.split()
        version, t_blockcharges, t_imaginaryblock, nspin, checksum = int(version), t_blockcharges=='T', t_imaginaryblock=='T', int(nspin), float(checksum)
        if t_blockcharges or  t_imaginaryblock:
            sys.exit("Reading "+chrg_fname+", not implemented case for current 'tBlockCharges tImaginaryBlock'.")
        chrg_list = []
        for chemsymbol in chemsymbol_list:
            n_chrgentry = orb_chrg_entry[max_orbital_dict[chemsymbol]]
            chrg_str = np.fromfile(chrgf, count=n_chrgentry, sep=' ')
            chrg_list.append( float(chrg_str[0]) )
    chrg_arry = np.array(chrg_list)
    return chrg_arry 
Example #4
0
def read(file_path, input_format=None):
    if input_format is None:
        input_format = os.path.splitext(file_path)[1][1:]
    # Read molecule file
    atoms = ase_read(file_path, format=input_format)

    # Get atom coordinates and names
    atom_coors = atoms.get_positions()
    atom_numbers = atoms.numbers
    atom_names = atoms.get_chemical_symbols()

    all_atoms = []
    for c, n in zip(atom_coors, atom_numbers):
        all_atoms.append((c[0], c[1], c[2], n))

    # Get unit cell parameters (converting from unit cell vectors)
    uc = ase_cellpar(atoms.cell)

    molecule = {
        'uc_size': [uc[0], uc[1], uc[2]],
        'uc_angle': [uc[3], uc[4], uc[5]],
        'atom_names': atom_names,
        'atom_coors': atom_coors,
        'atoms': all_atoms
    }

    return atoms, molecule
Example #5
0
	def __init__(self,surface_details):
		# Details about the surface
		if surface_details in [None,'none','None', {}]:
			self.surface = None
			self.place_cluster_where = None
		elif isinstance(surface_details['surface'], Atoms):
			self.surface = surface_details['surface']
		elif isinstance(surface_details['surface'], str):
			self.surface = ase_read(surface_details['surface'])
		else:
			exit('Error')
		if not self.surface == None:
			self.surface.center()
			self.place_cluster_where = surface_details['place_cluster_where']
Example #6
0
def import_surface(surface):
    """
    This method is designed to import the surface into the genetic algorithm

    :param surface: This is the surface that the cluster is optimised upon.
    :type  surface: str/ASE.Atoms.
    """
    if isinstance(surface, Atoms):
        pass
    elif isinstance(surface, str):
        surface = ase_read(surface)
    elif surface is None:
        surface = None
    else:
        print('Surface error in Cluster')
        exit('Error')
    for index in range(len(surface)):
        surface[index].type = 'surface'

    surface.centre()
    return surface
    def read(filename: str):
        """
        Reads cluster space from filename.

        Parameters
        ---------
        filename
            name of file from which to read cluster space
        """
        if isinstance(filename, str):
            tar_file = tarfile.open(mode='r', name=filename)
        else:
            tar_file = tarfile.open(mode='r', fileobj=filename)

        # read items
        items = pickle.load(tar_file.extractfile('items'))

        # read structure
        temp_file = tempfile.NamedTemporaryFile()
        temp_file.write(tar_file.extractfile('atoms').read())
        temp_file.seek(0)
        structure = ase_read(temp_file.name, format='json')

        tar_file.close()

        # ensure backward compatibility
        if 'symprec' not in items:  # pragma: no cover
            items['symprec'] = 1e-5
        if 'position_tolerance' not in items:  # pragma: no cover
            items['position_tolerance'] = items['symprec']

        cs = ClusterSpace(structure=structure,
                          cutoffs=items['cutoffs'],
                          chemical_symbols=items['chemical_symbols'],
                          symprec=items['symprec'],
                          position_tolerance=items['position_tolerance'])
        for indices in items['pruning_history']:
            cs._prune_orbit_list(indices)
        return cs
Example #8
0
def read(file_path, input_format=None):
    if input_format is None:
        input_format = os.path.splitext(file_path)[1][1:]
    # Read molecule file
    atoms = ase_read(file_path, format=input_format)

    # Get atom coordinates and names
    atom_coors = atoms.get_positions()
    atom_names = atoms.get_chemical_symbols()

    # Get unit cell parameters (converting from unit cell vectors)
    uc = ase_cellpar(atoms.cell)

    # Additional unit cell information (currently not used)
    sg = atoms.info['spacegroup'].symbol
    volume = atoms.get_volume()

    molecule = {'uc_size': [uc[0], uc[1], uc[2]],
                'uc_angle': [uc[3], uc[4], uc[5]],
                'atom_names': atom_names,
                'atom_coors': atom_coors}

    return atoms, molecule
Example #9
0
def Place_Already_Created_Clusters_In_Population(
        population, cluster_makeup, Minimisation_Function,
        vacuum_to_add_length, r_ij, rounding_criteria, surface,
        memory_operator, predation_operator, fitness_operator,
        previous_cluster_name):
    """
	This method will place any user created clusters into the population.

	:param population: The population
	:type  population: Organisms.GA.Population
	:param cluster_makeup: The makeup of the cluster
	:type  cluster_makeup: dict.
	:param Minimisation_Function: The minimisation function
	:type  Minimisation_Function: __func__
	:param vacuum_to_add_length: The amount of vacuum to place around the cluster
	:type  vacuum_to_add_length: float
	:param r_ij: The maximum distance that should be between atoms to be considered bonded. This value should be as large a possible, to reflected the longest bond possible between atoms in the cluster.
	:type  r_ij: float
	:param rounding_criteria: The number of decimal places to round the energy of clusters to.
	:type  rounding_criteria: int
	:param surface: This is the surface that the cluster is placed on. None means there is no surface.
	:type  surface: Organisms.GA.Surface
	:param memory_operator: The memory operator
	:type  memory_operator: Organisms.GA.Memory_Operator
	:param predation_operator: This is the predation operator 
	:type  predation_operator: Organisms.GA.Predation_Operator
	:param fitness_operator: This is the fitness operator
	:type  fitness_operator: Organisms.GA.Fitness_Operator
	:param previous_cluster_name: This is the name of the last cluster created in the genetic algorithm.
	:type  previous_cluster_name: int

	:returns The name of the most recently created cluster by this method in the population.
	:rtype   int

	"""
    print(
        'Checking to see if the user has any clusters in the folder ' +
        str(population.user_initialised_population_folder) +
        ' that the user would like to have inputted into the initalise population.'
    )
    # First, the definition will check the clusters if there is a population folder. If not, the user does not want to add any clusters to the initial population.
    if population.user_initialised_population_folder == None or population.user_initialised_population_folder == '':
        return 0
    if not os.path.exists(population.user_initialised_population_folder):
        print(
            'Error in def Place_Already_Created_Clusters_In_Population of class Population, in Population.py.'
        )
        print(
            'Yo, The path to the Intialised Population folder that you have specified does not exist.'
        )
        print('Check the path to this folder exists: ' +
              str(population.user_initialised_population_folder))
        print(
            'Note: This variable should include the folder itself as well in the path.'
        )
        exit('This program will end without doing anything.')
    ##############################################################################################################################################
    print(
        '################################################################################################################'
    )
    print(
        '################################################################################################################'
    )
    print('Will now initalise the population with clusters from:')
    print(str(population.user_initialised_population_folder))
    print(
        '################################################################################################################'
    )
    print(
        '################################################################################################################'
    )
    ##############################################################################################################################################
    # The folder nammed by the variable self.user_initialised_population_folder exists. Lets get whatever clusters are inside this folder.
    cluster_names = [
    ]  # holds the cluster dir values, which are equivalent to the number of the folder
    for cluster_name in os.listdir(
            population.user_initialised_population_folder):
        if cluster_name.startswith('.'):
            continue
        # If the cluster folder exists and the folder is numbered properly, then it is a cluster to be added into the GA program
        if os.path.isdir(
                os.path.join(population.user_initialised_population_folder,
                             cluster_name)) and cluster_name.isdigit():
            cluster_names.append(int(cluster_name))
        else:
            print(
                'Error in def Place_Already_Created_Clusters_In_Population of class Population, in Population.py.'
            )
            print('Check the Initialised Population folder ' +
                  str(population.user_initialised_population_folder) +
                  '. There is a folder which is not an integer')
            print(
                'All folders must be called by an integer as this is how the program names each cluster.'
            )
            print(
                'Check the folder in ' +
                str(population.user_initialised_population_folder) +
                ' to make sure all folders are clusters with integer labels.')
            print(
                'The folder that the GA is specifically having problems with is called '
                + str(cluster_name))
            print('This program will end without doing anything.')
            exit()
    cluster_names.sort()

    ##############################################################################################################################################
    # The clusters that the user has put into the population currently should be in sequential order starting from 1.
    def is_list_sequential(mylist):
        for index in range(0, len(mylist) - 1):
            if not mylist[index + 1] == mylist[index] + 1:
                return False
        return True

    if cluster_names == []:
        print(
            'Error in def Place_Already_Created_Clusters_In_Population of class Population, in Population.py.'
        )
        print(
            'There are no clusters in the Initialised Population in the path: '
            + str(population.user_initialised_population_folder))
        print('Check the Initialised Population folder ' +
              str(population.user_initialised_population_folder))
        print('This program will end without doing anything.')
        exit()
    elif not 1 in cluster_names:
        print(
            'Error in def Place_Already_Created_Clusters_In_Population of class Population, in Population.py.'
        )
        print(
            'One of the clusters in your already created population must have a dir/folder name that is the name "1"'
        )
        print('Check the cluster folders that are in the directory ' +
              str(population.user_initialised_population_folder))
        print('Folder names in ' +
              str(population.user_initialised_population_folder) +
              ' folder: ' + str(cluster_names))
        print('This program will end without doing anything.')
        exit()
    elif not is_list_sequential(cluster_names):
        print(
            'Error in def Place_Already_Created_Clusters_In_Population of class Population, in Population.py.'
        )
        print(
            'The names of the clusters/folders in the population folder "' +
            str(population.user_initialised_population_folder) +
            '" must be named by numbers in sequential order starting from "1"')
        print('Check the cluster folders that are in the directory ' +
              str(population.user_initialised_population_folder))
        print('Folder names in ' +
              str(population.user_initialised_population_folder) +
              ' folder: ' + str(cluster_names))
        print('This program will end without doing anything.')
        exit()
    ##############################################################################################################################################
    # The clusters will now be locally minimised as described by the def Minimisation_Function
    for cluster_name in cluster_names:
        ##########################################
        # Should be ok, but lets just double check at least that the clusters dir is between 1 and self.size
        if not cluster_name > 0:
            print(
                'Error in def Place_Already_Created_Clusters_In_Population of class Population, in Population.py.'
            )
            print('The dir name of this cluster is less than 0.')
            print('Dir of this cluster: ' + str(cluster_name))
            print('Cluster is located in ' +
                  str(population.user_initialised_population_folder + '/' +
                      str(cluster_name)))
            print('Check this out')
            import pdb
            pdb.set_trace()
            exit()
        elif not cluster_name < population.size + 1:
            toStringError = '******************************************************************\n'
            toStringError += 'There are more clusters in ' + str(
                population.user_initialised_population_folder
            ) + ' than allowed in this population.\n'
            toStringError += 'The population size for this genetic algorithm run is: ' + str(
                population.size) + '\n'
            toStringError += 'What we are going to do is not import any of the other clusters in the population, only keeping the following clusters\n'
            included_clusters_in_pop = population.get_cluster_names()
            toStringError += str(included_clusters_in_pop) + '\n'
            toStringError += 'We will exclude the following clusters from the population.\n'
            excluded_clusters_in_pop = []
            for cluster_name in cluster_names:
                if not cluster_name in included_clusters_in_pop:
                    excluded_clusters_in_pop.append(cluster_name)
            toStringError += str(excluded_clusters_in_pop) + '\n'
            toStringError += 'The genetic algorithm will continue. I hope you know what you are doing.\n'
            toStringError += '******************************************************************\n'
            print(toStringError)
            print(toStringError, file=sys.stderr)
            break
        ##########################################
        print('*****************************')
        xyz_files = [
            file for file in os.listdir(
                os.path.join(population.user_initialised_population_folder,
                             str(cluster_name))) if file.endswith('.xyz')
        ]
        # Check to find the xyz file that will be used. This xyz file will be considered unoptimsed
        if len(xyz_files) == 0:
            print(
                'Check cluster ' + str(cluster_name) +
                '. There is no .xyz file. The prorgram requires a .xyz file of this cluster so it knows the positions of the atoms in the cluster.'
            )
            exit()
        # File the cluster_name_UnOpt.xyz file. If it cant be found. Tell the user that it doesnt exist
        # and that this needs to be resolved by them. Note: we want to obtained the "_UnOpt.xyz" file,
        # NOT the _Opt.xyz. This is because we will be optimising it later, and for ease of the programming.
        # I know you might have already use the get_newly initialised_population.py program to get both the
        # unoptimised and optimised clusters, so you have already optimised the cluster, but this is just easier
        # overall. Take the optimised cluster obtained during the initialised_population.py program as a test to mkae sure
        # that the unoptimised cluster will not explode before it is used in the GA program. If you want to, you can change
        # this to use the "_Opt.xyz" file, and it probably wont be an issue. You may have to do some changing of the program,
        # but im sure it will be fine to do.
        for xyz_file in xyz_files:
            if str(cluster_name) + '_UnOpt.xyz' == xyz_file:
                break
        else:
            print(
                'Error in def Place_Already_Created_Clusters_In_Population of class Population, in Population.py.'
            )
            print('There is no .xyz file in Cluster (folder) ' +
                  str(cluster_name) + ' called " ' + str(cluster_name) +
                  '_Opt.xyz.')
            print(
                'This is the cluster xyz file that is used by the genetic algorithm to represent this cluster, as it is assume that it is that cluster, and the "_Opt" indicates that it has been locally optimised.'
            )
            print('Check folder ' + str(cluster_name) + ' in ' +
                  str(population.user_initialised_population_folder) +
                  ' for the file "' + str(str(cluster_name) + '_Opt.xyz') +
                  '".')
            print('Ending the genetic algorithm without doing anything.')
            exit()
        # Performed all checks, will now add cluster
        print('Adding Cluster ' + str(cluster_name) + ' to the population.')
        UnOpt_Cluster = ase_read(
            population.user_initialised_population_folder + '/' +
            str(cluster_name) + '/' + xyz_file)
        print(
            'Will locally optimise it as described by your def Minimisation_Function.'
        )
        stdout = sys.stdout
        output = StringIO()
        sys.stdout = output
        Opt_Cluster, converged, opt_information = Minimisation_Function(
            UnOpt_Cluster.copy(), population.name,
            cluster_name)  # note, self.name is the population name
        sys.stdout = stdout
        opt_information['output.txt'] = output.getvalue()
        if Exploded(
                Opt_Cluster, max_distance_between_atoms=r_ij
        ):  # make sure the randomised cluster has not split up when optimised.
            print(
                'Error in def Place_Already_Created_Clusters_In_Population of class Population, in Population.py.'
            )
            print("The optimised Cluster exploded. Check out why cluster " +
                  str(cluster_name) + ' has exploded by looking at cluster ' +
                  str(cluster_name) + 's AfterOpt.traj file.')
            print(
                'The program will now show the optimised and the unoptimised versions of cluster '
                + str(cluster_name))
            from ase.visualize import view
            view(UnOpt_Cluster)
            view(Opt_Cluster)
            print('This program will end without doing anything.')
            exit()
        elif not converged:
            print(
                'Error in def Place_Already_Created_Clusters_In_Population of class Population, in Population.py.'
            )
            print(
                "This Cluster did not converge when optimised. Check out why cluster "
                + str(cluster_name) +
                ' did not converge by at the following output from the stdout.'
            )
            print('*******************************************************')
            print(opt_information['output.txt'])
            print('*******************************************************')
            print(
                'The program will also show the optimised and the unoptimised versions of cluster '
                + str(cluster_name))
            from ase.visualize import view
            view(UnOpt_Cluster)
            view(Opt_Cluster)
            print('This program will end without doing anything.')
            exit()
        elif memory_operator.is_similar_cluster_in_memory_operator(
                Opt_Cluster):
            print(
                'Error in def Place_Already_Created_Clusters_In_Population, in Initialise_Population.py.'
            )
            print(
                "Cluster " + str(cluster_name) +
                ' in the population is too similar to one of the clusters in your memory operator database.'
            )
            print(
                'Check the clusters that you have included in your population and in the Memory Operator database'
            )
            print(
                'The program will now show the optimised version of cluster ' +
                str(cluster_name))
            from ase.visualize import view
            view(Opt_Cluster)
            print('This program will end without doing anything.')
            exit()
        initialised_cluster = Cluster(Opt_Cluster)
        initialised_cluster.verify_cluster(cluster_name, 0,
                                           vacuum_to_add_length,
                                           rounding_criteria)
        initialised_cluster.remove_calculator()
        # Set some of the details about the cluster that are needed for the population collection to save data to the population database.
        initialised_cluster.ever_in_population = True
        initialised_cluster.excluded_because_violates_predation_operator = False
        initialised_cluster.initial_population = True
        initialised_cluster.removed_by_memory_operator = False
        # Make sure this imported cluster has the correct chemical makeup for this genetic algorithm run.
        if not initialised_cluster.get_elemental_makeup() == cluster_makeup:
            print(
                'Error in def Place_Already_Created_Clusters_In_Population of class Population, in Population.py.'
            )
            print('Cluster ' + str(cluster_name) +
                  ' does not contain the correct chemical makeup.')
            print('Cluster ' + str(cluster_name) + ' makeup: ' +
                  str(initialised_cluster.get_elemental_makeup()))
            print('Desired makeup: ' + str(cluster_makeup))
            print('Check this out.')
            print('This program will end without doing anything')
            exit()
        index = cluster_name - 1
        print(
            'Adding Cluster ' + str(cluster_name) +
            ' that the user wants to placed into the population of the GA, before the generation cycles of the GA begins.'
        )
        population.add(
            index, initialised_cluster
        )  # Place the initialised cluster into the population ## self.Add_ClusterToPopulation(initialised_cluster,index,UnOpt_Cluster=UnOpt_Cluster,Optimisation_Information=opt_information)
    print('*****************************')
    ##############################################################################################################################################
    # Check to make sure that the clusters that have been entered in by the user do not violate the diversity scheme.
    #clusters_removed_from_pop, removed_clusters_report = Fitness_Factor_Scheme.Check_Initial_Population(return_report=True)
    fitness_operator.assign_initial_population_fitnesses()
    clusters_to_create, removed_clusters_report = Check_Population_against_predation_operator(
        population, predation_operator)
    #import pdb; pdb.set_trace()
    if not len(clusters_to_create) == 0:  #len(clusters_removed_from_pop):
        print(
            'Error in def Place_Already_Created_Clusters_In_Population of class Population, in Population.py.'
        )
        print(
            'Some of the clusters that you have placed in the population folder violate the Diversity operator: '
            + str(predation_operator.Predation_Switch))
        print(
            'Here is a list of the clusters that are the same as other clusters in this population:'
        )
        for cluster_kept_dir, clusters_removed_dirs in sorted(
                removed_clusters_report, key=lambda x: x[0]):
            clusters_removed_dirs.insert(0, cluster_kept_dir)
            print('Clusters: ' + str(clusters_removed_dirs) +
                  ' are considered identical by this diversity operator.')
        print('Check this out.')
        print('This program will end without doing anything')
        exit()
    ##############################################################################################################################################
    print('Finished importing clusters from ' +
          str(population.user_initialised_population_folder) +
          ' into the population')
    return population[-1].name
Example #10
0
def plot_displ_CLI(argv):
    """Command Line Wrapper for plot displacement Python function."""

    # -------------------------------------------------------------------------------
    # Argument parser
    # -------------------------------------------------------------------------------
    parser = argparse.ArgumentParser(description=plot_displ_CLI.__doc__)
    # Positional arguments
    # Optional args
    parser.add_argument('-s',
                        '--start',
                        dest='start',
                        default="POSCAR",
                        help='starting geometry (def: POSCAR);')
    parser.add_argument('-e',
                        '--end',
                        dest='end',
                        default="CONTCAR",
                        help='ending geometry (def: CONTCAR);')
    parser.add_argument(
        '-l',
        '--len',
        dest='v_len',
        type=float,
        default=1.0,
        help='scaling factor for displacement vectors visualization (def: 1);')
    parser.add_argument('--size',
                        dest='atm_scale',
                        type=float,
                        default=1.0,
                        help='scaling factor for atom size (def: 1);')
    parser.add_argument('--end_pt',
                        action='store_true',
                        dest='show_endpt',
                        help='show minimization endpoint')
    parser.add_argument('--no_norm',
                        action='store_true',
                        dest='norm',
                        help='normalize vectors to same size.')
    parser.add_argument('--rep',
                        dest='replica',
                        type=int,
                        nargs=3,
                        default=(1, 1, 1),
                        help='replicate systems along unit cell.')
    parser.add_argument('--uc',
                        dest='unitcell',
                        action='store_true',
                        help='plot unit cell.')
    parser.add_argument('--debug',
                        action='store_true',
                        dest='debug',
                        help='show debug informations.')
    parser.add_argument(
        '--mindisp',
        dest='mindisp',
        type=float,
        default=0.0,
        help='minimum displacement (in Angstrom) for arrow to be drawn')

    # -------------------------------------------------------------------------------
    # Initialize and check variables
    # -------------------------------------------------------------------------------
    args = parser.parse_args(argv)

    # Set up LOGGER
    c_log = logging.getLogger(__name__)
    # Adopted format: level - current function name - mess. Width is fixed as visual aid
    std_format = '[%(levelname)5s - %(funcName)10s] %(message)s'
    logging.basicConfig(format=std_format)
    c_log.setLevel(logging.INFO)
    # Set debug option
    if args.debug: c_log.setLevel(logging.DEBUG)

    c_log.debug(args)

    # -------------------------------------------------------------------------------
    # Load geometry
    # -------------------------------------------------------------------------------

    start = ase_read(args.start)
    del start.constraints
    try:
        start = ase_sort(start * args.replica)
    except Exception as e:
        c_log.error("Starting geom replication went wrong. Expect errors")

    end = ase_read(args.end)
    del end.constraints
    try:
        end = ase_sort(end * args.replica)
    except Exception as e:
        c_log.error("Ending geom replication went wrong. Expect errors")

    # -------------------------------------------------------------------------------
    # Plot
    # -------------------------------------------------------------------------------
    fig = plt.figure()
    fig.set_dpi(150)
    ax = fig.gca(projection='3d')

    ax = plot_displ(
        ax,
        start,
        end,
        atm_scale=args.atm_scale,  # size of atoms
        v_len=args.v_len,
        normalize=args.norm,
        mindisp=args.mindisp,  # displacement arrows
        plt_uc=args.unitcell,
        plt_endpt=args.show_endpt)  # To plot or not to plot
    plt.show()
    def read(cls,
             infile: Union[str, BinaryIO, TextIO],
             old_format: bool = False):
        """Reads data container from file.

        Parameters
        ----------
        infile
            file from which to read
        old_format
            If true use old json format to read runtime data; default to false

        Raises
        ------
        FileNotFoundError
            if file is not found (str)
        ValueError
            if file is of incorrect type (not a tarball)
        """
        if isinstance(infile, str):
            filename = infile
        else:
            filename = infile.name

        if not tarfile.is_tarfile(filename):
            raise TypeError('{} is not a tar file'.format(filename))

        with tarfile.open(mode='r', name=filename) as tf:
            # file with structures
            with tempfile.NamedTemporaryFile() as fobj:
                fobj.write(tf.extractfile('atoms').read())
                fobj.flush()
                structure = ase_read(fobj.name, format='json')

            # file with reference data
            with tempfile.NamedTemporaryFile() as fobj:
                fobj.write(tf.extractfile('reference_data').read())
                fobj.flush()
                with open(fobj.name, encoding='utf-8') as fd:
                    reference_data = json.load(fd)

            # init DataContainer
            dc = cls(structure=structure,
                     ensemble_parameters=reference_data['parameters'])

            # overwrite metadata
            dc._metadata = reference_data['metadata']

            for tag, value in reference_data['last_state'].items():
                if tag == 'random_state':
                    value = tuple(
                        tuple(x) if isinstance(x, list) else x for x in value)
                dc._last_state[tag] = value

            # add runtime data from file
            with tempfile.NamedTemporaryFile() as fobj:
                fobj.write(tf.extractfile('runtime_data').read())
                fobj.seek(0)
                if old_format:
                    runtime_data = pd.read_json(fobj)
                    data = runtime_data.sort_index(ascending=True)
                    dc._data_list = data.T.apply(
                        lambda x: x.dropna().to_dict()).tolist()
                else:
                    dc._data_list = np.load(
                        fobj, allow_pickle=True)['arr_0'].tolist()

        dc._observables = set([key for data in dc._data_list for key in data])
        dc._observables = dc._observables - {'mctrial'}

        return dc
Example #12
0
 def read(self, *args, **kwargs):
     return ase_to_pyiron(ase_read(*args, **kwargs))
Example #13
0
    def create_structure(self, results_dict, output_folder):
        """ create the output structure """
        opt_type = results_dict.get("opt_type", None)
        if opt_type == "polymer":
            if "final_coords" not in results_dict:
                return None, "ERROR_STRUCTURE_PARSING"
            final_coords = results_dict.pop("final_coords")
            if "structure" not in self.node.inputs:
                self.logger.error("the input structure node is not set")
                return None, "ERROR_MISSING_INPUT_STRUCTURE"
            if not set(final_coords.keys()).issuperset(["id", "x", "y", "z", "label"]):
                self.logger.error(
                    'expected final_coords to contain ["id", "x", "y", "z", "label"]'
                )
                return None, "ERROR_STRUCTURE_PARSING"
            if not final_coords["id"] == list(range(1, len(final_coords["id"]) + 1)):
                self.logger.error("the final_coords ids were not ordered 1,2,3,...")
                return None, "ERROR_STRUCTURE_PARSING"
            if (
                not final_coords["label"]
                == self.node.inputs.structure.get_ase().get_chemical_symbols()
            ):
                self.logger.error(
                    "the final_coords labels are != to the input structure symbols"
                )
                return None, "ERROR_STRUCTURE_PARSING"
            try:
                validate_1d_geometry(self.node.inputs.structure)
            except Exception as err:
                self.logger.error(str(err))
                return None, "ERROR_STRUCTURE_PARSING"
            out_structure = self.node.inputs.structure.clone()
            positions = []
            for x, y, z in zip(final_coords["x"], final_coords["y"], final_coords["z"]):
                # x are fractional and y,z are cartesian
                positions.append([x * out_structure.cell[0][0], y, z])
            out_structure.reset_sites_positions(positions)
        elif opt_type == "surface":
            self.logger.error(
                "creating output structures for surface optimisations has not yet been implemented"
            )
            return None, "ERROR_STRUCTURE_PARSING"
        else:
            cif_file = self.node.get_option("out_cif_file_name")
            if cif_file not in output_folder.list_object_names():
                self.logger.error("the output cif file is missing")
                return None, "ERROR_CIF_FILE_MISSING"

            # We do not use this method, since currently different kinds are set for each atom
            # see aiidateam/aiida_core#2942
            # NOTE cif files are read as binary, by default, since aiida-core v1.0.0b3
            # with output_folder.open(cif_file, mode="rb") as handle:
            #     cif = DataFactory('cif')(file=handle)
            # structure = cif.get_structure(converter="ase")

            with warnings.catch_warnings():
                # ase.io.read returns a warnings that can be ignored
                # UserWarning: crystal system 'triclinic' is not interpreted for space group 1.
                # This may result in wrong setting!
                warnings.simplefilter("ignore", UserWarning)
                with output_folder.open(cif_file, mode="r") as handle:
                    atoms = ase_read(handle, index=":", format="cif")[-1]
            atoms.set_tags(0)

            if self.node.get_option("use_input_kinds"):

                if "structure" not in self.node.inputs:
                    self.logger.error("the input structure node is not set")
                    return None, "ERROR_MISSING_INPUT_STRUCTURE"

                in_structure = self.node.inputs.structure
                in_atoms = in_structure.get_ase()

                if in_atoms.get_chemical_symbols() != atoms.get_chemical_symbols():
                    self.logger.error(
                        "the input and cif structures have different atomic configurations"
                    )
                    return None, "ERROR_CIF_INCONSISTENT"

                out_structure = in_structure.clone()
                out_structure.set_cell(atoms.cell)
                out_structure.reset_sites_positions(atoms.positions)

            else:
                out_structure = DataFactory("structure")(ase=atoms)

        return out_structure, None
Example #14
0
def build_emitter_from_file(uc_file, filename="emitter.txt", z_axis=(0,0,1),
                            x_axis="auto", y_axis="auto", emitter_radius=100,
                            emitter_side_height=50, vacuum_radius=25):
    """
    Build an emitter (set of nodes, TAPSim style) based on a
    unit cell structure file (`uc_file`). Any file format
    supported by ASE can be used.
    """

    if x_axis == "auto" and y_axis == "auto":
        if 0.99 < np.dot(z_axis, (1, 0, 0)) < 1.01:
            x_axis = tuple(np.cross(z_axis, (1, 0, 0)))
        else:
            x_axis = tuple(np.cross(z_axis, (0, 1, 0)))
        y_axis = tuple(np.cross(z_axis, x_axis))

    R = emitter_radius + vacuum_radius

    atoms = ase_read(uc_file)
    pts = atoms.get_positions()

    IDS = {}
    elt_id = 10
    for e in set(atoms.get_chemical_symbols()):
        IDS[e] = str(elt_id)
        elt_id += 10

    supercell_dimensions = (
        (int(math.ceil((2*R)/max([pt[0] for pt in pts])))+1, 0, 0),
        (0, int(math.ceil((2*R)/max([pt[1] for pt in pts])))+1, 0),
        (0, 0, int(math.ceil((emitter_side_height+R)/max([pt[2] for pt in pts])))+1)
    )

    atoms = make_supercell(atoms, supercell_dimensions)
    pts = atoms.get_positions()

    cx = np.mean([pt[0] for pt in pts])
    cy = np.mean([pt[1] for pt in pts])
    min_z = min([pt[2] for pt in pts])

    emitter_points, vacuum_points, bottom_points = [], [], []
    number = 0
    for atom in atoms:
        pt = atom.position
        pt = [pt[0], pt[1], pt[2]-min_z]
        if (pt[2] < 1e-5 and (pt[0]-cx)**2+(pt[1]-cy)**2<R**2):
            pt = [pt[0], pt[1], 0.0]
            pt = [i*1e-10 for i in pt]
            pt.append(2)  # bottom ID
            number += 1
            bottom_points.append(pt)
        elif (pt[2]<emitter_side_height and (pt[0]-cx)**2+(pt[1]-cy)**2\
                <emitter_radius**2):
            pt = [i*1e-10 for i in pt]
            pt.append(IDS[atom.symbol])  # emitter ID
            number += 1
            emitter_points.append(pt)
        elif (pt[0]-cx)**2+(pt[1]-cy)**2+(pt[2]-emitter_side_height)**2\
                <emitter_radius**2:
            pt = [i*1e-10 for i in pt]
            pt.append(IDS[atom.symbol])  # emitter ID
            number += 1
            emitter_points.append(pt)
        elif (pt[2]<emitter_side_height and (pt[0]-cx)**2+(pt[1]-cy)**2<R**2):
            pt = [i*1e-10 for i in pt]
            pt.append(0)  # vacuum ID
            number += 1
            vacuum_points.append(pt)
        elif (pt[0]-cx)**2+(pt[1]-cy)**2+(pt[2]-emitter_side_height)**2<R**2:
            pt = [i*1e-10 for i in pt]
            pt.append(0)  # vacuum ID
            number += 1
            vacuum_points.append(pt)

    with open(filename, "w") as e:
        n_nodes = number
        e.write("ASCII {} 0 0\n".format(n_nodes))
        for pt in emitter_points + vacuum_points + bottom_points:
                # It's required that the coordinates be
                # separated by a tab character (^I), not
                # by regular spaces.
                e.write("	".join([str(i) for i in pt]))
                e.write("\n")
        comment = ["#"]
        comment += [" {}={}".format(IDS[elt], elt) for elt in IDS]
        e.write("{}\n".format(" ".join(comment)))
#!/usr/bin/env python3
"""Get a reasonable number of nodes Nn on Iridis5 given the size N of the system.

From experience, up to 6 atoms are fine on 1 node (40CPUs) for using PBE with Encut 650eV Kdens=17x17x1.
Thus, reserve Nn=ceil(N/6+1/2) nodes, up to a maximum of 4 (more than 160 CPUs VASP becoms sluggish).
"""
import sys, math
from ase.io import read as ase_read

geom = ase_read(sys.argv[1], format='vasp')
Nn = math.ceil(len(geom)/6)
if Nn > 4: Nn = 4
print(Nn)