def Return_U_from_Aniso_Expand(inputs, new_crystal_matrix, coordinate_file,
                               Parameter_file, Program, output_file_name,
                               molecules_in_coord):

    # Converting the crystal matrix parameter to lattice parameters
    new_lattice_parameters = Ex.crystal_matrix_to_lattice_parameters(
        Ex.array_to_triangle_crystal_matrix(new_crystal_matrix))

    # Determining the file ending of the coordinate file
    file_ending = psf.assign_coordinate_file_ending(Program)

    # Determine the input coordinate files lattice parameters
    old_lattice_parameters = psf.Lattice_parameters(Program, coordinate_file)

    # Expand input coordinate file using the new lattice parameters
    Ex.Expand_Structure(inputs,
                        coordinate_file,
                        'lattice_parameters',
                        output_file_name,
                        dlattice_parameters=new_lattice_parameters[:6] -
                        old_lattice_parameters)
    # Computing the potential energy of the new expanded structure
    U = psf.Potential_energy(
        output_file_name + file_ending, Program,
        Parameter_file=Parameter_file) / molecules_in_coord
    return U
def gradient_output(T, Program, Coordinate_file):
    write_out('//////////////// Gradient at ' + str(T) +
              'K ////////////////\n')
    lattice_parameters = psf.Lattice_parameters(Program, Coordinate_file)
    write_out('Lattice vectors [Ang.^3] = \n')
    numpy_write_out(lattice_parameters[:3])
    write_out('Lattice angles [Degrees] = \n')
    numpy_write_out(lattice_parameters[3:])
def step_RK(index, T, Program, Coordinate_file):
    write_out('///   RUNGE-KUTTA Step ' + str(index + 1) + ' at T = ' +
              str(T) + 'K   ///   \n')
    lattice_parameters = psf.Lattice_parameters(Program, Coordinate_file)
    write_out('Lattice vectors [Ang.^3] = \n')
    numpy_write_out(lattice_parameters[:3])
    write_out('Lattice angles [Degrees] = \n')
    numpy_write_out(lattice_parameters[3:])
def constrained_minimization(inputs,
                             Coordinate_file,
                             Program,
                             Parameter_file=''):
    # Determining the file ending of the coordinate file
    file_ending = psf.assign_coordinate_file_ending(Program)

    # Determining the lattice parameters and volume of the input coordinate file
    lp_0 = psf.Lattice_parameters(Program, Coordinate_file)
    V0 = Pr.Volume(lattice_parameters=lp_0)
    cm_0 = Ex.triangle_crystal_matrix_to_array(
        Ex.Lattice_parameters_to_Crystal_matrix(lp_0))

    bnds = np.matrix([[cm_0[0] - cm_0[0] * 0.2, cm_0[0] + cm_0[0] * 0.2],
                      [cm_0[1] - cm_0[1] * 0.2, cm_0[1] + cm_0[1] * 0.2],
                      [cm_0[2] - cm_0[2] * 0.2, cm_0[2] + cm_0[2] * 0.2],
                      [cm_0[3] - cm_0[0] * 0.2, cm_0[3] + cm_0[0] * 0.2],
                      [cm_0[4] - cm_0[0] * 0.2, cm_0[4] + cm_0[0] * 0.2],
                      [cm_0[5] - cm_0[0] * 0.2, cm_0[5] + cm_0[0] * 0.2]])

    output = scipy.optimize.minimize(
        Return_U_from_Aniso_Expand,
        cm_0, (inputs, Coordinate_file, Parameter_file, Program,
               'constV_minimize', 4),
        method='SLSQP',
        constraints=({
            'type':
            'eq',
            'fun':
            lambda cm: np.linalg.det(Ex.array_to_triangle_crystal_matrix(cm)) -
            V0
        }),
        bounds=bnds,
        tol=1e-08,
        options={
            'ftol': float(1e-6),
            'disp': True,
            'eps': float(1e-4)
        })

    dlattice_parameters = Ex.crystal_matrix_to_lattice_parameters(
        Ex.array_to_triangle_crystal_matrix(output.x)) - lp_0
    Ex.Expand_Structure(inputs,
                        Coordinate_file,
                        'lattice_parameters',
                        'constV_minimize',
                        dlattice_parameters=dlattice_parameters)
    subprocess.call(['mv', 'constV_minimize' + file_ending, Coordinate_file])
Beispiel #5
0
def Isotropic_Change_Lattice_Parameters(volume_fraction_change, Program,
                                        Coordinate_file):
    """
    This function returns the change in lattice parameters for isotropic expansion/compression based off of a given 
    change in volume fraction

    **Required Inputs
    volume_fraction_change = Volume of the new desired strucutre over the volume of the previous structure
    Program = 'Tinker' for Tinker Molecular Modeling
              'Test' for a test run
    Coordinate_file = file containing lattice parameters of the previous strucuture
    """
    # Calling the lattice parameters
    lattice_parameters = psf.Lattice_parameters(Program, Coordinate_file)

    # Calculating the new isotropic lattice parameters
    dlattice_parameters = lattice_parameters * volume_fraction_change**(
        1 / 3.) - lattice_parameters

    # Setting changes in angles to zero because they do not change in isotropic expansion
    dlattice_parameters[3:] = 0.
    return dlattice_parameters
def Get_Aniso_Gruneisen_Wavenumbers(gruneisen, wavenumber_ref,
                                    crystal_matrix_ref,
                                    strained_coordinate_file, program):
    r"""
    Computes the isotropic wavenumbers using the Gruneisen parmaeters due to an isotropic volume change to the crystal
    lattice.

    Parameters
    ----------
    gruneisen: List[float]
        Anisotropic Gruneisen parameters.
    wavenumbers_ref: List[float]
        Wavenumbers [cm$^{-1}$] of the lattice minimum structure.
    crystal_matrix_ref: List[float]
        Lattice tensor [$\AA$] of the lattice minimum structure.
    strained_coordinate_file: float
        Coordinate file of the anisotropically expanded crystal that the wavenumbers need to be computed for.
    program: str
        Program being used.

    Returns
    -------
    wavenumbers: List[float]
        Wavenumbers [cm$^{-1}$] of the crystal structure in the strained crystal.
    """
    # Determining the strain placed on the expanded crystal relative to the reference matrix
    new_crystal_matrix = Ex.Lattice_parameters_to_Crystal_matrix(
        psf.Lattice_parameters(program, strained_coordinate_file))
    applied_strain = Pr.RotationFree_StrainArray_from_CrystalMatrix(
        crystal_matrix_ref, new_crystal_matrix)

    # Setting a blank array for new wavenumbers
    wavenumbers = np.zeros(len(wavenumber_ref))

    # Computing the change to each wavenumber due to the current strain
    for i in np.arange(3, len(wavenumbers), 1):
        wavenumbers[i] = wavenumber_ref[i] * np.exp(
            -1. * np.sum(np.dot(applied_strain, gruneisen[i])))
    return wavenumbers
Beispiel #7
0
def Expand_Structure(inputs, Coordinate_file, Expansion_type, output_file_name,
                     **keyword_parameters):
    """
    This function expands a coordinate file either based off of an inputted change in lattice vectors or crystal 
        lattice matrix

    **Required Inputs
    Coordinate_file = file containing lattice parameters (and coordinates)
    Program = 'Tinker' for Tinker Molecular Modeling
              'Test' for a test run
    Expansion_type = 'lattice parameters' expanding the structure by lattice parameters ([a,b,c,alpha,beta,gamma])
                   = 'crystal_matrix' expanding the strucutre by changes in the crystal matrix
    molecules_in_coord = number of molecules in the coordinate file
    Output = string to name expanded coordinate file
    
    **Optional Inputs
    dlattice_vectors = Changes in lattice parameters
    dcrystal_matrix = changes in crystal matrix
    Parameter_file = program specific file containingforce field parameters
    """
    if inputs.program == 'Test':
        coordinates = ''
        lattice_parameters = psf.Lattice_parameters(inputs.program,
                                                    Coordinate_file)
        crystal_matrix = Lattice_parameters_to_Crystal_matrix(
            lattice_parameters)
        if Expansion_type == 'lattice_parameters':
            lattice_parameters = lattice_parameters + keyword_parameters[
                'dlattice_parameters']
        elif Expansion_type == 'strain':
            crystal_matrix = np.dot(
                (np.identity(3) + keyword_parameters['strain']),
                crystal_matrix)
            lattice_parameters = crystal_matrix_to_lattice_parameters(
                crystal_matrix)
        elif Expansion_type == 'crystal_matrix':
            crystal_matrix = crystal_matrix + keyword_parameters[
                'dcrystal_matrix']
            lattice_parameters = crystal_matrix_to_lattice_parameters(
                crystal_matrix)

    else:
        # Grabbing the lattice parameters and coordiantes
        lattice_parameters = psf.Lattice_parameters(inputs.program,
                                                    Coordinate_file)
        coordinates = psf.return_coordinates(inputs.program, Coordinate_file,
                                             lattice_parameters)

        # Converting the lattice parameters to the lattice tensor
        crystal_matrix = Lattice_parameters_to_Crystal_matrix(
            lattice_parameters)

        # Setting up the number of atoms per molecule as specified by the user
        if type(inputs.multi_nmols) == type(None):
            coordinate_center_of_mass = np.zeros(
                (inputs.number_of_molecules, 3))
            atoms_per_molecule = np.zeros(inputs.number_of_molecules)
            atoms_per_molecule[:] = len(
                coordinates[:, 0]) // inputs.number_of_molecules
        else:
            coordinate_center_of_mass = np.zeros((sum(inputs.multi_nmols), 3))
            atoms_per_molecule = np.zeros(sum(inputs.multi_nmols))

            placement = 0
            for i in range(len(inputs.multi_nmols)):
                atoms_per_molecule[
                    placement:placement +
                    inputs.multi_nmols[i]] = inputs.multi_atomspermol[i]
                placement += inputs.multi_nmols[i]

        # Determining the molecules center and removing that to expand the crystal
        for i in range(len(atoms_per_molecule)):
            lb = int(sum(atoms_per_molecule[:i]))
            #lb = i*atoms_per_molecule
            ub = int(sum(atoms_per_molecule[:i + 1]))
            #ub = (i+1)*atoms_per_molecule
            coordinate_center_of_mass[i, :] = np.mean(coordinates[lb:ub],
                                                      axis=0)
            coordinates[lb:ub] = np.subtract(coordinates[lb:ub],
                                             coordinate_center_of_mass[i, :])

        # Center of mass coordinates converted to fractional coordinates
        coordinate_center_of_mass = np.dot(np.linalg.inv(crystal_matrix),
                                           coordinate_center_of_mass.T).T

        # Computing the new crystal matrix
        if Expansion_type == 'lattice_parameters':
            lattice_parameters = lattice_parameters + keyword_parameters[
                'dlattice_parameters']
            crystal_matrix = Lattice_parameters_to_Crystal_matrix(
                lattice_parameters)
        elif Expansion_type == 'strain':
            crystal_matrix = np.dot(
                (np.identity(3) + keyword_parameters['strain']),
                crystal_matrix)
            lattice_parameters = crystal_matrix_to_lattice_parameters(
                crystal_matrix)
            crystal_matrix = Lattice_parameters_to_Crystal_matrix(
                lattice_parameters)
        elif Expansion_type == 'crystal_matrix':
            crystal_matrix = crystal_matrix + keyword_parameters[
                'dcrystal_matrix']
            lattice_parameters = crystal_matrix_to_lattice_parameters(
                crystal_matrix)

        # Converting the center of mass to cartesian coordinates, but expanded to the new crystal matrix
        coordinate_center_of_mass = np.dot(crystal_matrix,
                                           coordinate_center_of_mass.T).T

        # Adding the atoms back to the expanded center of mass
        for i in range(len(atoms_per_molecule)):
            lb = int(sum(atoms_per_molecule[:i]))
            #lb = i*atoms_per_molecule
            ub = int(sum(atoms_per_molecule[:i + 1]))
            #ub = (i+1)*atoms_per_molecule
            coordinates[lb:ub] = np.subtract(
                coordinates[lb:ub], -1 * coordinate_center_of_mass[i, :])

    # Outputing the new coordinate file
    psf.output_new_coordinate_file(inputs.program, Coordinate_file,
                                   inputs.tinker_parameter_file, coordinates,
                                   lattice_parameters, output_file_name,
                                   inputs.min_rms_gradient)
Beispiel #8
0
def EOS_TvP_Gru_0T_0P(Method, Temperature, Pressure, Program, Output,
                      Coordinate_file, Parameter_file, molecules_in_coord,
                      properties_to_save, Statistical_mechanics,
                      Gruneisen_Vol_FracStep, Wavenum_Tol, min_RMS_gradient,
                      eq_of_state, cp2kroot, V0, B, dB, E0):

    # Calculating the Gruneisen parameter with the lattice minimum structure
    print("   Calculating the isotropic Gruneisen parameter")
    Gruneisen, Wavenumber_Reference, Volume_Reference = Wvn.Call_Wavenumbers(
        Method,
        min_RMS_gradient,
        Output=Output,
        Coordinate_file=Coordinate_file,
        Program=Program,
        Gruneisen_Vol_FracStep=Gruneisen_Vol_FracStep,
        molecules_in_coord=molecules_in_coord,
        Parameter_file=Parameter_file,
        cp2kroot=cp2kroot)

    # Setting up an array to store the properties
    properties = np.zeros((len(Pressure), len(Temperature), 14))
    properties[:, :, 7:13] = psf.Lattice_parameters(Program, Coordinate_file)

    for i in range(len(Pressure)):
        for j in range(len(Temperature)):
            V = scipy.optimize.minimize(
                Gibbs_EOS_temperature_pressure,
                V0,
                args=(Method, min_RMS_gradient, Gruneisen,
                      Wavenumber_Reference, V0, B, dB, E0, eq_of_state,
                      Temperature[j], Statistical_mechanics, Pressure[i],
                      molecules_in_coord),
                method='Nelder-Mead',
                tol=1.e-15).x

            wavenumbers = Wvn.Call_Wavenumbers(
                Method,
                min_RMS_gradient,
                Gruneisen=Gruneisen,
                Wavenumber_Reference=Wavenumber_Reference,
                Volume_Reference=V0,
                New_Volume=V)

            properties[i, j, 0] = Temperature[j]
            properties[i, j, 1] = Pressure[i]
            properties[i, j, 3] = eos.EV_EOS(V, V0, B, dB, E0,
                                             eq_of_state) / molecules_in_coord
            properties[i, j, 4] = Pr.Vibrational_Helmholtz(
                Temperature[j], wavenumbers,
                Statistical_mechanics) / molecules_in_coord
            properties[i, j,
                       5] = Pr.PV_energy(Pressure[i], V) / molecules_in_coord
            properties[i, j, 2] = sum(properties[i, j, 3:6])
            properties[i, j, 6] = V
            properties[i, j, 7:10] = (V / V0)**(1 / 3) * properties[i, j, 7:10]
            properties[i, j, 13] = Pr.Vibrational_Entropy(
                Temperature[j], wavenumbers,
                Statistical_mechanics) / molecules_in_coord

    Save_Properties_PvsT(properties, properties_to_save, Output, Method,
                         Statistical_mechanics)
    sys.exit()
def Setup_Anisotropic_Gruneisen(inputs):
    r"""
    Computes the anisotropic Gruneisen parameters of the lattice minimum structure

    Parameters
    ----------
    inputs: Class
        Contains all user defined values and filled in with default program values

    Returns
    -------
    gruneisen: List[float]
        Anisotropic Gruneisen parameters.
    wavenumbers_ref: List[float]
        Wavenumbers [cm$^{-1}$] of the lattice minimum structure.
    """
    # Determining the file ending for the program used
    file_ending = psf.assign_coordinate_file_ending(inputs.program)

    # Determining if the anisotropic Gruneisen parameters have already been calculated
    # Typically, this take a long time. It may be advantageous to parallelize this in the future.
    re_run = False
    if os.path.isfile('GRU_wvn.npy') and os.path.isfile('GRU_eigen.npy'):
        # Loading in previously computed Gruneisen parameters
        wavenumbers = np.load('GRU_wvn.npy')
        eigenvectors = np.load('GRU_eigen.npy')
        re_run = True
    else:
        # Computing the reference wavenumbers and eigenvectors (the lattice minimum structure fed in)
        wavenumbers_ref, eigenvectors_ref = psf.Wavenumber_and_Vectors(
            inputs.program, inputs.coordinate_file,
            inputs.tinker_parameter_file)

        # Setting the number of vibrational modes
        number_of_modes = int(len(wavenumbers_ref))
        number_of_atoms = psf.atoms_count(inputs.program,
                                          inputs.coordinate_file)

        # Setting a place to store all the wavenumbers and eigenvalues for the Gruenisen parameters
        wavenumbers = np.zeros((7, number_of_modes))
        eigenvectors = np.zeros((7, number_of_modes, 3 * number_of_atoms))
        wavenumbers[0] = wavenumbers_ref
        eigenvectors[0] = eigenvectors_ref

        # Out putting information for user output
        NO.start_anisoGru()

        # Saving that data computed thusfar in case the system crashes or times out
        np.save('GRU_eigen', eigenvectors)
        np.save('GRU_wvn', wavenumbers)

    # Cycling through the six principle six principal strains
    for i in range(6):
        if re_run and (wavenumbers[i + 1, 3] != 0.):
            # Skipping a given strain if the wavenumbers have previously been computed and loaded in
            pass
        else:
            # Expanding the lattice minimum structure in the direction of the i-th principal strain
            applied_strain = np.zeros(6)
            applied_strain[i] = inputs.gruneisen_matrix_strain_stepsize
            Ex.Expand_Structure(
                inputs,
                inputs.coordinate_file,
                'strain',
                'temp',
                strain=Ex.strain_matrix(applied_strain),
                crystal_matrix=Ex.Lattice_parameters_to_Crystal_matrix(
                    psf.Lattice_parameters(inputs.program,
                                           inputs.coordinate_file)))

            # Computing the strained wavenumbers and eigenvectors
            wavenumbers_unorganized, eigenvectors_unorganized = psf.Wavenumber_and_Vectors(
                inputs.program, 'temp' + file_ending,
                inputs.tinker_parameter_file)

            # Determining how the strained eigenvectors match up with the reference structure
            z, weight = matching_eigenvectors_of_modes(
                number_of_modes, eigenvectors[0], eigenvectors_unorganized)
            NO.GRU_weight(
                weight
            )  # Writing out the precision of matching the modes with one another

            # Re-organizing the expanded wavenumbers
            wavenumbers[i + 1], eigenvectors[i + 1] = reorder_modes(
                z, wavenumbers_unorganized, eigenvectors_unorganized)

            # Saving the eigenvectors and wavenumbers
            np.save('GRU_eigen', eigenvectors)
            np.save('GRU_wvn', wavenumbers)

            # Removing the strained coordinate file
            subprocess.call(['rm', 'temp' + file_ending])

    # Calculating the Gruneisen parameters due to the six principal strains
    gruneisen = np.zeros((number_of_modes, 6))
    for i in range(6):
        # Calculating the Gruneisen parameters
        gruneisen[3:, i] = -(np.log(wavenumbers[i + 1, 3:]) - np.log(wavenumbers[0, 3:])) \
                           / inputs.gruneisen_matrix_strain_stepsize
    return gruneisen, wavenumbers[0]
def Setup_Isotropic_Gruneisen(inputs):
    r"""
    Computes the isotropic Gruneisen parameters of the lattice minimum structure

    Parameters
    ----------
    inputs: Class
        Contains all user defined values and filled in with default program values

    Returns
    -------
    gruneisen: List[float]
        Isotropic Gruneisen parameters.
    wavenumbers_ref: List[float]
        Wavenumbers [cm$^{-1}$] of the lattice minimum structure.
    volume_ref: float
        Volume [$\AA^{3}$] of the lattice minimum structure.
    """

    # Change in lattice parameters for expanded structure
    dLattice_Parameters = Ex.Isotropic_Change_Lattice_Parameters(
        (1 + inputs.gruneisen_volume_fraction_stepsize), inputs.program,
        inputs.coordinate_file)

    # Determining wavenumbers of lattice strucutre and expanded structure
    lattice_parameters = psf.Lattice_parameters(inputs.program,
                                                inputs.coordinate_file)

    # Expanding structure
    Ex.Expand_Structure(inputs,
                        inputs.coordinate_file,
                        'lattice_parameters',
                        'temp',
                        dlattice_parameters=dLattice_Parameters)

    # File ending of the coordinate file
    file_ending = psf.assign_coordinate_file_ending(inputs.program)

    # Computing the reference wavenumbers and eigenvectors
    wavenumbers_ref, eigenvectors_ref = psf.Wavenumber_and_Vectors(
        inputs.program, inputs.coordinate_file, inputs.tinker_parameter_file)
    number_of_modes = len(wavenumbers_ref)  # Number of vibrational modes

    # Computing the strained wavenumbers and eigenvectors
    wavenumbers_unorganized, eigenvectors_unorganized = psf.Wavenumber_and_Vectors(
        inputs.program, 'temp' + file_ending, inputs.tinker_parameter_file)

    # Determining how the strained eigenvectors match up with the reference structure
    z, weight = matching_eigenvectors_of_modes(number_of_modes,
                                               eigenvectors_ref,
                                               eigenvectors_unorganized)

    # Outputing information for user output
    NO.start_isoGru()
    NO.GRU_weight(weight)

    # Re-organizing the expanded wavenumbers
    wavenumbers_organized, eigenvectors_organized = reorder_modes(
        z, wavenumbers_unorganized, eigenvectors_unorganized)

    # Calculating the volume of the lattice minimum and expanded structure
    volume_ref = Pr.Volume(lattice_parameters=lattice_parameters)
    volume_expand = volume_ref + inputs.gruneisen_volume_fraction_stepsize * volume_ref

    # Computing the Gruneisen parameters
    gruneisen = np.zeros(len(wavenumbers_ref))
    gruneisen[3:] = -(np.log(wavenumbers_ref[3:]) - np.log(wavenumbers_organized[3:])) / \
                    (np.log(volume_ref) - np.log(volume_expand))
    for x in range(0, len(gruneisen)):
        if wavenumbers_ref[x] == 0:
            gruneisen[x] = 0.0

    # Removing extra files created in process
    subprocess.call(['rm', 'temp' + file_ending])
    return gruneisen, wavenumbers_ref, volume_ref
Beispiel #11
0
def temperature_lattice_dynamics(inputs, data, input_file='input.yaml'):
    # Geometry and lattice optimizing the input structure
    if inputs.tinker_xtalmin and (inputs.program == 'Tinker'):
        psf.tinker_xtalmin(inputs)
        inputs.tinker_xtalmin = False

    # Running the harmonic approximation
    if inputs.method == 'HA':
        print("Performing Harmonic Approximation")

        # Determining if the wavenumbers have already been calculated
        if os.path.isfile(inputs.output + '_' + inputs.method + '_WVN.npy'):
            # Loading in te wavenumbers
            wavenumbers = np.load(inputs.output + '_' + inputs.method + '_WVN.npy')
            print("   Importing wavenumbers from:" + inputs.output + '_' + inputs.method + '_WVN.npy')
        else:
            # Computing the wavenumbers and saving them
            print("   Computing wavenumbers of coordinate file")
            wavenumbers = Wvn.Call_Wavenumbers(inputs, Coordinate_file=inputs.coordinate_file,
                                               Parameter_file=inputs.tinker_parameter_file)
            np.save(inputs.output + '_' + inputs.method + '_WVN', wavenumbers)

        # Making sure all wavenumbers are within the user specified tolerance
        if all(wavenumbers[:3] < inputs.wavenumber_tolerance) and \
                all(wavenumbers[:3] > -1. * inputs.wavenumber_tolerance):
            print("   All wavenumbers are greater than tolerance of: " + str(inputs.wavenumber_tolerance) + " cm^-1")
            properties = Pr.Properties_with_Temperature_and_Pressure(inputs, inputs.coordinate_file, wavenumbers)
            print("   All properties have been saved in " + inputs.output + "_raw.npy")
            np.save(inputs.output + '_raw', properties)
            print("   Saving user specified properties in indipendent files:")
            Pr.Save_Properties_2D(inputs, properties)
        exit()
    else:
        if not os.path.isdir('Cords'):
            print("Creating directory 'Cords/' to store structures along Gibbs free energy path")
            subprocess.call(['mkdir', 'Cords'])

    # Expanding the crystal with the zero point energy
    if (inputs.statistical_mechanics == 'Quantum') and (inputs.coordinate_file != 'ezp_minimum' + psf.assign_coordinate_file_ending(inputs.program)):
        if any(inputs.gradient_matrix_fractions != 0.):
            crystal_matrix_array = Ex.triangle_crystal_matrix_to_array(Ex.Lattice_parameters_to_Crystal_matrix(
                psf.Lattice_parameters(inputs.program, inputs.coordinate_file)))
            LocGrd_dC = np.absolute(inputs.gradient_matrix_fractions * crystal_matrix_array)
            for i in range(len(LocGrd_dC)):
                if LocGrd_dC[i] == 0.:
                    LocGrd_dC[i] = inputs.gradient_matrix_fractions[i]
        else:
            LocGrd_dC = Ss.anisotropic_gradient_settings(inputs, data, input_file)

        TNA.anisotropic_gradient_expansion_ezp(inputs, LocGrd_dC)
        inputs.coordinate_file = 'ezp_minimum' + psf.assign_coordinate_file_ending(inputs.program)

    # Running through QHA
    if (inputs.method == 'SiQ') or (inputs.method == 'SiQg'):
        # Stepwise Isotropic QHA
        print("Performing Stepwise Isotropic Quasi-Harmonic Approximation")
        properties = TNA.stepwise_expansion(inputs)

        print("   Saving user specified properties in indipendent files:")
        Pr.Save_Properties_1D(inputs, properties)

    elif (inputs.method == 'GiQ') or (inputs.method == 'GiQg'):
        if inputs.gradient_vol_fraction == (0. or None):
            LocGrd_dV = Ss.isotropic_gradient_settings(inputs)
        else:
            V_0 = Pr.Volume(Program=inputs.program, Coordinate_file=inputs.coordinate_file)
            LocGrd_dV = inputs.gradient_vol_fraction * V_0
        # Gradient Isotropic QHA
        print("Performing Gradient Isotropic Quasi-Harmonic Approximation")
        properties = TNA.Isotropic_Gradient_Expansion(inputs, LocGrd_dV)

        print("   Saving user specified properties in indipendent files:")
        Pr.Save_Properties_1D(inputs, properties)
    elif (inputs.method == 'GaQ') or (inputs.method == 'GaQg'):
        if inputs.statistical_mechanics == 'Classical':
            if any(inputs.gradient_matrix_fractions != 0.):
                crystal_matrix_array = Ex.triangle_crystal_matrix_to_array(Ex.Lattice_parameters_to_Crystal_matrix(
                    psf.Lattice_parameters(inputs.program, inputs.coordinate_file)))
                LocGrd_dC = np.absolute(inputs.gradient_matrix_fractions * crystal_matrix_array)
                for i in range(len(LocGrd_dC)):
                    if LocGrd_dC[i] == 0.:
                        LocGrd_dC[i] = inputs.gradient_matrix_fractions[i]
            else:
                LocGrd_dC = Ss.anisotropic_gradient_settings(inputs, data, input_file)

        if inputs.anisotropic_type != '1D':
            print("Performing Gradient Anisotropic Quasi-Harmonic Approximation")
            properties = TNA.Anisotropic_Gradient_Expansion(inputs, LocGrd_dC)
            print("   Saving user specified properties in independent files:")
            Pr.Save_Properties_1D(inputs, properties)
        else:
            print("Performing 1D-Gradient Anisotropic Quasi-Harmonic Approximation")
            properties = TNA.Anisotropic_Gradient_Expansion_1D(inputs, LocGrd_dC)
            print("   Saving user specified properties in independent files:")
            Pr.Save_Properties_1D(inputs, properties)
        
    elif inputs.method == 'SaQply':
        print("Performing Quasi-Anisotropic Quasi-Harmonic Approximation")
        properties = TNA.stepwise_expansion(inputs)
        print("   Saving user specified properties in independent files:")
        Pr.Save_Properties_1D(inputs, properties)
    print("Lattice dynamic calculation is complete!")
Beispiel #12
0
def anisotropic_gradient_settings(inputs, data, input_file):
    # Determining the file ending based on the program
    file_ending = psf.assign_coordinate_file_ending(inputs.program)

    # Setting the energy cutoff
    cutoff = program_cutoff(inputs.program)

    # Fractional step sizes to take
    steps = np.array([
        5e-05, 1e-04, 5e-04, 1e-03, 5e-03, 1e-02, 5e-02, 1e-01, 5e-01, 1., 5.,
        1e01, 5e01, 1e02, 5e02, 1e03, 5e03, 1e04, 5e04
    ])

    # Number of total step sizes
    n_steps = len(steps)

    # Potential energy of input file and a place to store the expanded structures potential energy
    U_0 = psf.Potential_energy(inputs.coordinate_file, inputs.program, Parameter_file=inputs.tinker_parameter_file) / \
          inputs.number_of_molecules
    U = np.zeros((6, n_steps))

    # Determining the tensor parameters of the input file
    crystal_matrix = Ex.Lattice_parameters_to_Crystal_matrix(
        psf.Lattice_parameters(inputs.program, inputs.coordinate_file))
    crystal_matrix_array = Ex.triangle_crystal_matrix_to_array(crystal_matrix)

    LocGrd_CMatrix_FracStep = np.zeros(6)
    LocGrd_CMatrix_Step = np.zeros(6)
    for j in range(6):
        for i in range(n_steps):
            dlattice_matrix_array = np.zeros(6)
            dlattice_matrix_array[j] = np.absolute(crystal_matrix_array[j] *
                                                   steps[i])
            if np.absolute(crystal_matrix_array[j]) < 1e-4:
                dlattice_matrix_array[j] = steps[i]
            dlattice_matrix = Ex.array_to_triangle_crystal_matrix(
                dlattice_matrix_array)
            Ex.Expand_Structure(inputs,
                                inputs.coordinate_file,
                                'crystal_matrix',
                                inputs.output,
                                dcrystal_matrix=dlattice_matrix)
            U[j, i] = psf.Potential_energy(
                inputs.output + file_ending,
                inputs.program,
                Parameter_file=inputs.tinker_parameter_file
            ) / inputs.number_of_molecules
            subprocess.call(['rm', inputs.output + file_ending])
            if (U[j, i] - U_0) > cutoff:
                LocGrd_CMatrix_FracStep[j] = 10**np.interp(
                    cutoff, U[j, i - 1:i + 1] - U_0,
                    np.log10(steps[i - 1:i + 1]))
                LocGrd_CMatrix_Step[j] = np.absolute(
                    crystal_matrix_array[j] * LocGrd_CMatrix_FracStep[j])
                if np.absolute(crystal_matrix_array[j]) < 1e-4:
                    LocGrd_CMatrix_Step[j] = LocGrd_CMatrix_FracStep[j]
                break
        plt.scatter(np.log10(LocGrd_CMatrix_FracStep[j]),
                    cutoff,
                    marker='x',
                    color='r')
        plt.plot(np.log10(steps[:i + 1]),
                 U[j, :i + 1] - U_0,
                 linestyle='--',
                 marker='o',
                 label='C' + str(j + 1))

    # Plotting the results
    plt.xlabel('$\log({dC/C_{0}})$', fontsize=22)
    plt.ylabel('$\Delta U$ [kcal/mol]', fontsize=22)
    plt.ylim((0., 2 * cutoff))
    plt.axhline(y=cutoff, c='grey', linestyle='--')
    plt.legend(loc='upper right', ncol=2, fontsize=18)
    plt.tight_layout()
    plt.savefig(inputs.output + '_LocGrd_CMatrix_FracStep.pdf')
    plt.close()

    # Printing step size
    print("After analysis, LocGrd_CMatrix_FracStep = ",
          LocGrd_CMatrix_FracStep)
    data['gradient']['matrix_fractions'] = LocGrd_CMatrix_FracStep.tolist()
    with open(input_file, 'w') as yaml_file:
        yaml.dump(data, yaml_file, default_flow_style=False)
    # returning the value of dV
    return LocGrd_CMatrix_Step