uclchem.makerates.io_functions ============================== .. py:module:: uclchem.makerates.io_functions .. autoapi-nested-parse:: Functions to read in the species and reaction files and write output files. Module Contents --------------- Functions ~~~~~~~~~ .. autoapisummary:: uclchem.makerates.io_functions.array_to_string uclchem.makerates.io_functions.build_ode_string uclchem.makerates.io_functions.check_reaction uclchem.makerates.io_functions.copy_coolant_files uclchem.makerates.io_functions.find_reactant uclchem.makerates.io_functions.get_default_coolant_directory uclchem.makerates.io_functions.get_default_coolants uclchem.makerates.io_functions.get_desorption_freeze_partners uclchem.makerates.io_functions.kida_parser uclchem.makerates.io_functions.output_drops uclchem.makerates.io_functions.read_coolants_file uclchem.makerates.io_functions.read_grain_assisted_recombination_file uclchem.makerates.io_functions.read_reaction_file uclchem.makerates.io_functions.read_species_file uclchem.makerates.io_functions.replace_value_with_name uclchem.makerates.io_functions.species_ode_string uclchem.makerates.io_functions.strip_comments_from_row uclchem.makerates.io_functions.truncate_line uclchem.makerates.io_functions.write_evap_lists uclchem.makerates.io_functions.write_f90_constants uclchem.makerates.io_functions.write_jacobian uclchem.makerates.io_functions.write_network_file uclchem.makerates.io_functions.write_odes_f90 uclchem.makerates.io_functions.write_outputs uclchem.makerates.io_functions.write_python_constants uclchem.makerates.io_functions.write_reactions uclchem.makerates.io_functions.write_species Attributes ~~~~~~~~~~ .. autoapisummary:: uclchem.makerates.io_functions.FORTRAN_LINE_LENGTH uclchem.makerates.io_functions.logger .. py:function:: array_to_string(name: str, array: list | numpy.ndarray, type: str = 'int', parameter: bool = True) -> str Write an array to fortran source code. :param name: Variable name of array in Fortran :type name: str :param array: List of values of array :type array: list | np.ndarray :param type: The array's type. Must be one of "int", "float", "string" or "logical". Defaults to "int". :type type: str :param parameter: Whether the array is a Fortran PARAMETER (constant). Defaults to True. :type parameter: bool :returns: **outString** -- String containing the Fortran code to declare this array. :rtype: str :raises ValueError: Raises an error if type isn't "int", "float", "string" or "logical". .. py:function:: build_ode_string(species_list: list[uclchem.makerates.species.Species], reaction_list: list[uclchem.makerates.reaction.Reaction], enable_rates_storage: bool = False) -> str Build the ODE string. A long, complex function that does the messy work of creating the actual ODE code to calculate the rate of change of each species. Test any change to this code thoroughly because ODE mistakes are very hard to spot. :param species_list: List of species in network :type species_list: list[Species] :param reaction_list: List of reactions in network :type reaction_list: list[Reaction] :param enable_rates_storage: Enable the writing of the rates to the disk. Default = False. :type enable_rates_storage: bool :returns: **ode_string** -- One long string containing the entire ODE fortran code. :rtype: str .. py:function:: check_reaction(reaction_row: list[Any], keep_list: list[str]) -> bool Check a row parsed from a reaction file and checks it only contains acceptable things. It checks if all species in the reaction are present, and adds the temperature range is none is specified. :param reaction_row: List parsed from a reaction file and formatted to be able to called Reaction(reaction_row) :type reaction_row: list[Any] :param keep_list: list of species strings that are acceptable in the reactant or product bits of row :type keep_list: list[str] :returns: Whether the row contains acceptable entries. :rtype: bool :raises ValueError: If custom desorb or freeze reactions contain species not in the species list. .. py:function:: copy_coolant_files(source_dir: str | pathlib.Path | None = None) -> None Copy coolant data files to the package data directory for installation. This function copies .dat files from the source coolant directory (typically Makerates/data/collisional_rates/) to src/uclchem/data/collisional_rates/ so they can be installed with the package via meson. :param source_dir: Optional source directory. If None, uses get_default_coolant_directory(). Default = None. :type source_dir: str | Path | None :raises FileNotFoundError: If source directory doesn't exist or contains no .dat files. .. py:function:: find_reactant(species_list: list[str], reactant: str) -> int Try to find a reactant in the species list. :param species_list: A list of species in the network :type species_list: list[str] :param reactant: The reactant to be indexed :type reactant: str :returns: The index of the reactant, if it is not found, 9999 :rtype: int .. py:function:: get_default_coolant_directory(user_specified: str | pathlib.Path = '') -> str Get the collisional rates directory path for use during makerates. :param user_specified: User-specified directory from config. If empty, searches standard locations relative to CWD. (Default value = '') :type user_specified: str | Path :returns: Absolute directory path to collisional rate data files. :rtype: str .. py:function:: get_default_coolants() -> list[dict[str, str]] Get the default coolant configuration for UCLCHEM. :returns: List of coolant dictionaries with 'file' and 'name' keys. :rtype: list[dict[str, str]] .. py:function:: get_desorption_freeze_partners(reaction_list: list[uclchem.makerates.reaction.Reaction]) -> list[int] Every desorption has a corresponding freeze out eg desorption of #CO and freeze of CO. This find the corresponding freeze out for every desorb so that when desorb>>freeze we can turn off freeze out in UCLCHEM. :param reaction_list: Reactions in network :type reaction_list: list[Reaction] :returns: **partners** -- list of indices of freeze out reactions matching order of desorptions. :rtype: list[int] .. py:function:: kida_parser(kida_file: str | pathlib.Path) -> list[list[str | int | float]] Parse rows of a KIDA file. KIDA used a fixed format file so we read each line in the chunks they specify and use python built in classes to convert to the necessary types. NOTE KIDA defines some of the same reaction types to UMIST but with different names and coefficients. We fix that by converting them here. :param kida_file: path to KIDA file :type kida_file: str | Path :returns: rows (list[list[Any]]) :rtype: list[list[str | int | float]] .. py:function:: output_drops(dropped_reactions: list[list[str]], output_dir: str | pathlib.Path | None = None, write_files: bool = True) -> None Write the reactions that are dropped to disk/logs. :param dropped_reactions: The reactions that were dropped :type dropped_reactions: list[list[str]] :param output_dir: The directory that dropped_reactions.csv will be written to. Default = None (writes to current directory). :type output_dir: str | Path | None :param write_files: Whether or not to write the file. Defaults to True. :type write_files: bool .. py:function:: read_coolants_file(file_name: str | pathlib.Path) -> list[dict] Read a YAML file specifying coolants. The file should contain either a single mapping or a list of mappings where each mapping contains 'file' and 'name' keys. 'file' must be a bare filename (no path). :param file_name: Path to coolants file. :type file_name: str | Path :returns: Normalized list of coolant dicts. :rtype: list[dict] :raises ValueError: If the yaml-parsed data is not a dictionary, or list of dictionaries. :raises ValueError: If the "file" entries in coolants_file are not bare filenames. .. py:function:: read_grain_assisted_recombination_file(file_name: str | pathlib.Path) -> dict[str, numpy.ndarray] Read a grain assisted recombination file. :param file_name: file path of grain assisted recombination data :type file_name: str | Path :returns: **gar_parameters** -- Database for grain-activated recombination reactions. :rtype: dict[str, np.ndarray] .. py:function:: read_reaction_file(file_name: str | pathlib.Path, species_list: list[uclchem.makerates.species.Species], ftype: Literal['UMIST', 'KIDA', 'UCL']) -> tuple[list[uclchem.makerates.reaction.Reaction], list[list[str]]] Read in a reaction file of any kind (UCL, UMIST, KIDA), and. produces a list of reactions for the network, filtered by species_list. :param file_name: A file name for the reaction file to read. :type file_name: str | Path :param species_list: A list of chemical species to be used in the reading. :type species_list: list[Species] :param ftype: 'UMIST','UCL', or 'KIDA' to describe format of file_name :type ftype: Literal['UMIST', 'KIDA', 'UCL'] :returns: * **reactions** (*list[Reaction]*) -- List of kept reactions. * **dropped_reactions** (*list[list[str]]*) -- List of raw CSV rows for dropped reactions. :raises ValueError: If reaction file type is not one of ["UMIST", "UCL", "KIDA"]. .. py:function:: read_species_file(file_name: str | pathlib.Path) -> tuple[list[uclchem.makerates.species.Species], list[uclchem.makerates.species.Species]] Read in a Makerates species file. :param file_name: path to file containing the species list :type file_name: str | Path :returns: * **species_list** (*list[Species]*) -- List of Species objects * **user_defined_bulk** (*list[Species]*) -- List of user defined bulk species :raises IndexError: If there is an error parsing a line in the file. .. py:function:: replace_value_with_name(string: str, value: int | float, replace_string: str, truncate: bool = True) -> str Replace all instances of ``value`` with a string ``replace_string``. Uses func:`array_to_string` to determine how ``value`` would be formatted as a string. :param string: string to reformat :type string: str :param value: value to replace :type value: int | float :param replace_string: string to put instead of ``value`` :type replace_string: str :param truncate: Whether to truncate the line using func:`truncate_line`. Default = True. :type truncate: bool :returns: **replaced_string** -- string with ``value`` replaced. :rtype: str :raises TypeError: If ``value`` is not an instance of ``int`` or ``float``. .. rubric:: Examples >>> replace_value_with_name("(/0,1,2/)", 2, "X") '(/0,1,X/)' >>> replace_value_with_name("(/0.0000e+00,1.0000e+00,2.0000e+00/)", 2.0, "X") '(/0.0000e+00,1.0000e+00,X/)' >>> # Replaces all instances of 'value' >>> replace_value_with_name("(/0.0000e+00,1.0000e+00,2.0000e+00,1.0000e+00/)", 1.0, "X") '(/0.0000e+00,X,2.0000e+00,X/)' .. py:function:: species_ode_string(n: int, species: uclchem.makerates.species.Species) -> str Build the string of Fortran code for a species once it's loss and gains. strings have been produced. :param n: Index of species in python format :type n: int :param species: species object :type species: Species :returns: the fortran code for the rate of change of the species :rtype: str .. py:function:: strip_comments_from_row(row: list[str], comment_char: str = '!') -> list[str] Strip comments from a separated line. :param row: List of strings. :type row: list[str] :param comment_char: Character indicating the beginning of a comment. Default = "!". :type comment_char: str :returns: **row** -- List of strings, with the final string adjusted by removing everything after `comment_char` (and any whitespace). :rtype: list[str] .. py:function:: truncate_line(input_string: str, line_length: int = 72) -> str Take a string and adds line endings at regular intervals. Keeps us from overshooting fortran's line limits and, frankly, makes for nicer ode.f90 even if human readability isn't very important :param input_string: Line of code to be truncated :type input_string: str :param line_length: rough line length. Default = 72. :type line_length: int :returns: **result** -- Code string with line endings at regular intervals :rtype: str .. py:function:: write_evap_lists(network_file: IO[str], species_list: list[uclchem.makerates.species.Species]) -> int Write evaporation list to network file. Two phase networks mimic episodic thermal desorption seen in lab (see Viti et al. 2004) by desorbing fixed fractions of material at specific temperatures. Three phase networks just use binding energy and that fact we set binding energies in bulk to water by default. This function writes all necessary arrays to the network file so these processes work. :param network_file: Open file handle to which the network code is being written :type network_file: IO[str] :param species_list: List of species in network :type species_list: list[Species] :returns: number of ice species :rtype: int :raises NameError: If a species desorbs as another species that is not in the species list. .. py:function:: write_f90_constants(replace_dict: dict[str, Any], output_file_name: pathlib.Path, template_file_path: str | pathlib.Path = 'fortran_templates') -> None Write the physical reactions to the f2py_constants.f90 file after every. run of makerates, this ensures the Fortran and Python bits are compatible. :param replace_dict: The dictionary with keys to replace :type replace_dict: dict[str, Any] :param output_file_name: The path to target f2py_constants.f90 file :type output_file_name: Path :param template_file_path: The file to use as the template. (Default value = 'fortran_templates') :type template_file_path: str | Path .. py:function:: write_jacobian(file_name: pathlib.Path, species_list: list[uclchem.makerates.species.Species]) -> None Write jacobian in Modern Fortran. This has never improved UCLCHEM's speed. and so is not used in the code as it stands. Current only works for three phase model. :param file_name: Path to jacobian file :type file_name: Path :param species_list: List of species AFTER being processed by build_ode_string :type species_list: list[Species] .. py:function:: write_network_file(file_name: pathlib.Path, network: uclchem.makerates.network.Network, enable_rates_storage: bool = False, gar_database: dict[str, numpy.ndarray] | None = None) -> None Write the Fortran code file that contains all network information for UCLCHEM. This includes lists of reactants, products, binding energies, formationEnthalpies and so on. :param file_name: The file name where the code will be written. :type file_name: Path :param network: A Network object built from lists of species and reactions. :type network: Network :param enable_rates_storage: Enable storage of writing rates to files. Default = False. :type enable_rates_storage: bool :param gar_database: Database for grain-activated recombination reactions. Default = None. :type gar_database: dict[str, np.ndarray] | None :raises AssertionError: If exothermicity is non-zero but ``enable_rates_storage`` is ``False``. .. py:function:: write_odes_f90(file_name: pathlib.Path, species_list: list[uclchem.makerates.species.Species], reaction_list: list[uclchem.makerates.reaction.Reaction], enable_rates_storage: bool = False) -> None Write the ODEs in Modern Fortran. This is an actual code file. :param file_name: Path to file where code will be written :type file_name: Path :param species_list: List of species describing network :type species_list: list[Species] :param reaction_list: List of reactions describing network :type reaction_list: list[Reaction] :param enable_rates_storage: Enable storage of writing rates to files. Default = False. :type enable_rates_storage: bool .. py:function:: write_outputs(network: uclchem.makerates.network.Network, python_src_dir: pathlib.Path, fortran_src_dir: pathlib.Path, enable_rates_storage: bool = False, gar_database: dict[str, numpy.ndarray] | None = None, coolants: list[dict] | None = None, coolant_data_dir: str | pathlib.Path | None = '') -> None Write the ODE and Network fortran source files to the fortran source. :param network: The makerates Network class :type network: Network :param python_src_dir: Directory to write Python source files (species.csv, reactions.csv). :type python_src_dir: Path :param fortran_src_dir: Directory to write Fortran source files (odes.f90, network.f90, f2py_constants.f90). :type fortran_src_dir: Path :param enable_rates_storage: Enable storage of writing rates to files. Default = False. :type enable_rates_storage: bool :param gar_database: Database for grain-activated recombination reactions. Default = None. :type gar_database: dict[str, np.ndarray] | None :param coolants: List of coolants or None. If None, use default list of coolants. See `get_default_coolants().` :type coolants: list[dict] | None :param coolant_data_dir: User-specified directory from config. If empty, searches standard locations relative to CWD. (Default value = '') :type coolant_data_dir: str | Path | None :raises ValueError: If coolants entries do not have a key "file" or the file names are not bare file names. :raises ValueError: If coolants start with "o-" or "p-" for ortho and para, but no `conversion_factor` is given in the dictionary. :raises ValueError: If coolants have parent species specified that are not in the network. .. py:function:: write_python_constants(replace_dict: dict[str, int], python_constants_file: pathlib.Path) -> None Write the python constants to the constants.py file (deprecated). As of the latest version, constants.py reads directly from the f2py_constants module, so this function is no longer needed. It's kept for backward compatibility but does nothing. :param replace_dict: Dict with keys to replace and their values (ignored) :type replace_dict: dict[str, int] :param python_constants_file: Path to the target constant files (ignored) :type python_constants_file: Path .. py:function:: write_reactions(file_name: pathlib.Path, reaction_list: list[uclchem.makerates.reaction.Reaction]) -> None Write the human readable reaction file. :param file_name: path to output file :type file_name: Path :param reaction_list: List of reaction objects for network :type reaction_list: list[Reaction] .. py:function:: write_species(file_name: str | pathlib.Path, species_list: list[uclchem.makerates.species.Species]) -> None Write the human readable species file. Note UCLCHEM doesn't use this file. :param file_name: path to output file :type file_name: str | Path :param species_list: List of species objects for network :type species_list: list[Species] .. py:data:: FORTRAN_LINE_LENGTH :value: 72 .. py:data:: logger