Example #1
0
    def test_log_bde_report(self):
        """Test the log_bde_report() function"""
        path = os.path.join(arc_path, 'arc', 'testing', 'bde_report_test.txt')
        bde_report = {
            'aniline': {
                (1, 2): 431.43,
                (5, 8): 465.36,
                (6, 9): 458.70,
                (3, 10): 463.16,
                (4, 11): 463.16,
                (7, 12): 458.70,
                (1, 13): 372.31,
                (1, 14): 372.31,
                (5, 6): 'N/A'
            }
        }
        xyz = """N       2.28116100   -0.20275000   -0.29653100
        C       0.90749600   -0.08067400   -0.11852200
        C       0.09862900   -1.21367300   -0.02143500
        C       0.30223500    1.17638000   -0.08930600
        C      -1.87236600    0.16329100    0.13332800
        C      -1.27400900   -1.08769400    0.10342700
        C      -1.07133200    1.29144700    0.03586700
        H      -2.94554700    0.25749800    0.23136900
        H      -1.88237600   -1.98069300    0.17844600
        H       0.55264300   -2.19782900   -0.04842100
        H       0.91592000    2.06653500   -0.16951700
        H      -1.51965000    2.27721000    0.05753400
        H       2.68270800   -1.06667200    0.02551200
        H       2.82448700    0.59762700   -0.02174900"""
        aniline = ARCSpecies(label='aniline',
                             xyz=xyz,
                             smiles='c1ccc(cc1)N',
                             bdes=['all_h', (1, 2), (5, 6)])
        spc_dict = {'aniline': aniline}
        plotter.log_bde_report(path, bde_report, spc_dict)

        with open(path, 'r') as f:
            content = f.read()
        expected_content = """ BDE report for aniline:
  Pivots           Atoms        BDE (kJ/mol)
 --------          -----        ------------
 (1, 13)           N - H           372.31
 (1, 14)           N - H           372.31
 (1, 2)            N - C           431.43
 (6, 9)            C - H           458.70
 (7, 12)           C - H           458.70
 (3, 10)           C - H           463.16
 (4, 11)           C - H           463.16
 (5, 8)            C - H           465.36
 (5, 6)            C - C           N/A


"""
        self.assertEqual(content, expected_content)
Example #2
0
def process_arc_project(
    thermo_adapter: str,
    kinetics_adapter: str,
    project: str,
    project_directory: str,
    species_dict: dict,
    reactions: list,
    output_dict: dict,
    bac_type: Optional[str] = None,
    sp_level: Optional[Level] = None,
    freq_scale_factor: float = 1.0,
    compute_thermo: bool = True,
    compute_rates: bool = True,
    compute_transport: bool = False,
    T_min: tuple = None,
    T_max: tuple = None,
    T_count: int = 50,
    lib_long_desc: str = '',
    rmg_database: Optional[RMGDatabase] = None,
    compare_to_rmg: bool = True,
    three_params: bool = True,
) -> None:
    """
    Process an ARC project, generate thermo and rate coefficients using statistical mechanics (statmech).

    Args:
        thermo_adapter (str): The software to use for calculating thermodynamic data.
        kinetics_adapter (str): The software to use for calculating rate coefficients.
        project (str): The ARC project name.
        project_directory (str): The path to the ARC project directory.
        species_dict (dict): Keys are labels, values are ARCSpecies objects.
        reactions (list): Entries are ARCReaction objects.
        output_dict (dict): Keys are labels, values are output file paths.
                            See Scheduler for a description of this dictionary.
        bac_type (str, optional): The bond additivity correction type. 'p' for Petersson- or 'm' for Melius-type BAC.
                                  ``None`` to not use BAC.
        sp_level (Level, optional): The level of theory used for energy corrections.
        freq_scale_factor (float, optional): The harmonic frequencies scaling factor.
        compute_thermo (bool, optional): Whether to compute thermodynamic properties for the provided species.
        compute_rates (bool, optional): Whether to compute high pressure limit rate coefficients.
        compute_transport (bool, optional): Whether to compute transport properties.
        T_min (tuple, optional): The minimum temperature for kinetics computations, e.g., (500, 'K').
        T_max (tuple, optional): The maximum temperature for kinetics computations, e.g., (3000, 'K').
        T_count (int, optional): The number of temperature points between ``T_min`` and ``T_max``.
        lib_long_desc (str, optional): A multiline description of levels of theory for the resulting RMG libraries.
        rmg_database (RMGDatabase, optional): The RMG database object.
        compare_to_rmg (bool, optional): If ``True``, ARC's calculations will be compared against estimations
                                         from RMG's database.
        three_params (bool, optional): Compute rate coefficients using the modified three-parameter Arrhenius equation
                                       format (``True``, default) or classical two-parameter Arrhenius equation format
                                       (``False``).
    """
    T_min = T_min or (300, 'K')
    T_max = T_max or (3000, 'K')
    if isinstance(T_min, (int, float)):
        T_min = (T_min, 'K')
    if isinstance(T_max, (int, float)):
        T_max = (T_max, 'K')
    T_count = T_count or 50

    species_for_thermo_lib, unconverged_species = list(), list()
    rxns_for_kinetics_lib, unconverged_rxns = list(), list()
    species_for_transport_lib = list()
    bde_report = dict()

    output_directory = os.path.join(project_directory, 'output')
    libraries_path = os.path.join(output_directory, 'RMG libraries')
    if not os.path.isdir(output_directory):
        os.makedirs(output_directory)

    # guarantees that the adapters are supported:
    thermo_adapter_label = StatmechEnum(thermo_adapter)
    kinetics_adapter_label = StatmechEnum(kinetics_adapter)

    # 1. Rates
    if compute_rates:
        for reaction in reactions:
            species_converged = True
            considered_labels = list(
            )  # species labels considered in this reaction
            if output_dict[reaction.ts_label]['convergence']:
                for species in reaction.r_species + reaction.p_species:
                    if species.label in considered_labels:
                        # consider cases where the same species appears in a reaction both as a reactant
                        # and as a product (e.g., H2O that catalyzes a reaction).
                        continue
                    considered_labels.append(species.label)
                    if output_dict[species.label]['convergence']:
                        statmech_adapter = statmech_factory(
                            statmech_adapter_label=kinetics_adapter_label,
                            output_directory=output_directory,
                            output_dict=output_dict,
                            bac_type=None,
                            sp_level=sp_level,
                            freq_scale_factor=freq_scale_factor,
                            species=species,
                        )
                        statmech_adapter.compute_thermo(kinetics_flag=True)
                    else:
                        logger.error(
                            f'Species {species.label} did not converge, cannot compute a rate coefficient '
                            f'for {reaction.label}')
                        unconverged_species.append(species)
                        species_converged = False
                if species_converged:
                    statmech_adapter = statmech_factory(
                        statmech_adapter_label=kinetics_adapter_label,
                        output_directory=output_directory,
                        output_dict=output_dict,
                        bac_type=None,
                        sp_level=sp_level,
                        freq_scale_factor=freq_scale_factor,
                        reaction=reaction,
                        species_dict=species_dict,
                        T_min=T_min,
                        T_max=T_max,
                        T_count=T_count,
                        three_params=three_params,
                    )
                    statmech_adapter.compute_high_p_rate_coefficient()
                    if reaction.kinetics is not None:
                        rxns_for_kinetics_lib.append(reaction)
                    else:
                        unconverged_rxns.append(reaction)
            else:
                unconverged_rxns.append(reaction)
        if rxns_for_kinetics_lib:
            plotter.save_kinetics_lib(rxn_list=rxns_for_kinetics_lib,
                                      path=libraries_path,
                                      name=project,
                                      lib_long_desc=lib_long_desc)

    # 2. Thermo
    if compute_thermo:
        for species in species_dict.values():
            if (species.compute_thermo or species.e0_only
                ) and output_dict[species.label]['convergence']:
                statmech_adapter = statmech_factory(
                    statmech_adapter_label=thermo_adapter_label,
                    output_directory=output_directory,
                    output_dict=output_dict,
                    bac_type=bac_type,
                    sp_level=sp_level,
                    freq_scale_factor=freq_scale_factor,
                    species=species,
                )
                statmech_adapter.compute_thermo(kinetics_flag=False,
                                                e0_only=species.e0_only)
                if species.thermo is not None:
                    species_for_thermo_lib.append(species)
                elif not species.e0_only and species not in unconverged_species:
                    unconverged_species.append(species)
            elif species.compute_thermo and not output_dict[species.label]['convergence'] \
                    and species not in unconverged_species:
                unconverged_species.append(species)
        if species_for_thermo_lib:
            plotter.save_thermo_lib(species_list=species_for_thermo_lib,
                                    path=libraries_path,
                                    name=project,
                                    lib_long_desc=lib_long_desc)

    # 3. Transport
    if compute_transport:
        for species in species_dict.values():
            if output_dict[species.label]['job_types'][
                    'onedmin'] and output_dict[species.label]['convergence']:
                pass
                # todo
        if species_for_transport_lib:
            plotter.save_transport_lib(species_list=species_for_thermo_lib,
                                       path=libraries_path,
                                       name=project,
                                       lib_long_desc=lib_long_desc)

    # 4. BDE
    for species in species_dict.values():
        # looping again to make sure all relevant Species.e0 attributes were set
        if species.bdes is not None:
            bde_report[species.label] = process_bdes(label=species.label,
                                                     species_dict=species_dict)
    if bde_report:
        bde_path = os.path.join(project_directory, 'output', 'BDE_report.txt')
        plotter.log_bde_report(path=bde_path,
                               bde_report=bde_report,
                               spc_dict=species_dict)

    # Comparisons
    if compare_to_rmg:
        try:
            load_rmg_database(rmg_database=rmg_database,
                              species_dict=species_dict,
                              output_dict=output_dict)
        except Exception as e:
            logger.error(f'Could not load the RMG database! Got:\n{e}')
        else:
            compare_thermo(species_for_thermo_lib=species_for_thermo_lib,
                           rmg_database=rmg_database,
                           output_directory=output_directory)
            compare_rates(rxns_for_kinetics_lib,
                          rmg_database,
                          output_directory=output_directory,
                          T_min=T_min,
                          T_max=T_max,
                          T_count=T_count)
            compare_transport(species_for_transport_lib,
                              rmg_database,
                              output_directory=output_directory)

    write_unconverged_log(unconverged_species=unconverged_species,
                          unconverged_rxns=unconverged_rxns,
                          log_file_path=os.path.join(
                              output_directory, 'unconverged_species.log'))
    clean_output_directory(project_directory)