Source code for dpest.wheat.ceres.cul

import yaml
from dpest.functions import *

[docs] def cul( cultivar = None, cul_file_path = None, output_path = None, new_template_file_extension = None, header_start = None, tpl_first_line = None, minima = None, maxima = None, mrk = '~', **parameters_grouped ): """ Create a TPL file for CERES Wheat based on a cultivar CUL file with specified parameter modifications. Args: cultivar (str): Name of the cultivar to modify. This argument is required. cul_file_path (str): Full path to the cultivar CUL file. This argument is required. output_path (str): Directory to save the generated TPL file. Defaults to the current working directory. new_template_file_extension (str): Extension for the generated template file (e.g., "tpl"). header_start (str): Identifier for the header row in the CUL file. Default is '@VAR#'. tpl_first_line (str): First line to include in the TPL file. Default is 'ptf ~'. minima (str): Row identifier for the minima parameter values. Default is '999991'. maxima (str): Row identifier for the maxima parameter values. Default is '999992'. parameters_grouped (dict): A dictionary where keys are group names and values are comma-separated strings of parameter names to include in the TPL file. If not provided, defaults are loaded from the configuration file. mrk (str, optional): Primary marker delimiter character for the template file. Defaults to '~'. Returns: dict: A dictionary containing: - 'cultivar_parameters': Current parameter values for the specified cultivar. - 'minima_parameters': Minima values for all parameters. - 'maxima_parameters': Maxima values for all parameters. - 'parameters_grouped': The grouped parameters used for template generation. str: The full path to the generated TPL file (output_new_file_path). Raises: ValueError: If required arguments are missing or invalid values are encountered. FileNotFoundError: If the specified CUL file does not exist. Exception: For any other unexpected errors. """ # Defaul variable values yml_cultivar_block = 'CULTIVAR_TPL_FILE' yaml_file_variables = 'FILE_VARIABLES' yaml_parameters = 'PARAMETERS' try: ## Get the yaml_data # Get the directory of the current script current_dir = os.path.dirname(os.path.abspath(__file__)) # Construct the path to arguments.yml arguments_file = os.path.join(current_dir, 'arguments.yml') # Ensure the YAML file exists if not os.path.isfile(arguments_file): raise FileNotFoundError(f"YAML file not found: {arguments_file}") # Load YAML configuration with open(arguments_file, 'r') as yml_file: yaml_data = yaml.safe_load(yml_file) # Validate cultivar if cultivar is None: raise ValueError("The 'cultivar' argument is required and must be specified by the user.") # Validate cul_file_path validated_path = validate_file(cul_file_path, '.CUL') # Validate marker delimiters using the validate_marker() function mrk = validate_marker(mrk, "mrk") # Get the cultivar template file variables function_arguments = yaml_data[yml_cultivar_block][yaml_file_variables] if new_template_file_extension is None: new_template_file_extension = function_arguments['new_template_file_extension'] if header_start is None: header_start = function_arguments['header_start'] if tpl_first_line is None: tpl_first_line = function_arguments['tpl_first_line'] if minima is None: minima = str(function_arguments['minima']) if maxima is None: maxima = str(function_arguments['maxima']) if parameters_grouped == {}: parameters_grouped = yaml_data[yml_cultivar_block][yaml_parameters] parameters_grouped = {key: ', '.join(value) for key, value in parameters_grouped.items()} # Combine all the groups of parameters into a list parameters = [] for key, value in parameters_grouped.items(): group_parameters = [param.strip() for param in value.split(',')] # Strip spaces from each parameter parameters.extend(group_parameters) # Add the group parameters to the main list # Read the CUL file file_content = read_dssat_file(cul_file_path) lines = file_content.split('\n') # Locate header and target lines header_line_number = next(idx for idx, line in enumerate(lines) if line.startswith(header_start)) header_line = lines[header_line_number] # Get the number of the line that contains the parameters of the specified cultivar cultivar_line_number = find_cultivar(file_content, header_start, cultivar, cul_file_path) if isinstance(cultivar_line_number, str): # Error message returned raise ValueError(cultivar_line_number) minima_line_number = find_cultivar(file_content, header_start, minima, cul_file_path) if isinstance(minima_line_number, str): # Error message returned raise ValueError(minima_line_number) maxima_line_number = find_cultivar(file_content, header_start, maxima, cul_file_path) if isinstance( maxima_line_number, str): # Error message returned raise ValueError( maxima_line_number) # Extract parameter values for cultivar, minima, and maxima def extract_parameter_values(line_number): parameter_values = {} for parameter in parameters: try: par_position = find_parameter_position(header_line, parameter) parameter_value = lines[line_number][par_position[0]:par_position[1] + 1].strip() parameter_values[parameter] = parameter_value except Exception: raise ValueError(f"Parameter '{parameter}' does not exist in the header line of {cul_file_path}.") return parameter_values minima_parameter_values = extract_parameter_values(minima_line_number) maxima_parameter_values = extract_parameter_values(maxima_line_number) # Dictionary to store current parameter values current_parameter_values = {} # Iterate each parameter in the list to generate the template parameter_par_truncated = {} count = 0 for parameter in parameters: # Get the parameter position on the line par_position = find_parameter_position(header_line, parameter) # Extract the current value of the parameter from the line parameter_value = lines[cultivar_line_number][par_position[0]:par_position[1]+1].strip() # Store the current value in the dictionary current_parameter_values[parameter] = parameter_value # Get the length of a parameter including empty spaces char_compl = header_line[par_position[0]+1:par_position[1]+1] # Get the length of the parameter without empty characters char = char_compl.strip() # Calculate the number of available characters for the parameter available_space = len(char_compl) - 2 # Truncate or pad the parameter to fit within the available space if len(parameter) > available_space: truncated_parameter = parameter[:available_space] # Truncate the parameter # Save the parameter compleate name and truncated name into a dictionary parameter_par_truncated[parameter] = truncated_parameter.strip() else: truncated_parameter = parameter.ljust(available_space) # Add spaces to the parameter # Save the parameter compleate name and truncated name into a dictionary parameter_par_truncated[parameter] = truncated_parameter.strip() # Construct the variable template variable_template = f" {mrk}{truncated_parameter}{mrk}" # Extract the cultivar line to modify parameters cultivar_line = lines[cultivar_line_number] if count == 0: # Replace the content at the specified position with adjusted_template modified_line = ( cultivar_line[:par_position[0]] # Part of the line before the parameter + variable_template # Insert the adjusted template + cultivar_line[par_position[1] + 1:] # Part of the line after the parameter ) else: # Replace the content at the specified position with adjusted_template modified_line = ( modified_line[:par_position[0]] # Part of the line before the parameter + variable_template # Insert the adjusted template + modified_line[par_position[1] + 1:] # Part of the line after the parameter ) count += 1 # Insert the modified line back into the text lines[cultivar_line_number] = modified_line # Insert 'ptf' and marker at the beginning of the file content lines.insert(0, f"{tpl_first_line} {mrk}") # Output the updated text updated_text = "\n".join(lines) # Validate output_path output_path = validate_output_path(output_path) # Add the file name and extension to the path for the new file output_new_file_path = os.path.join(output_path, os.path.splitext(os.path.basename(cul_file_path))[0] + '_CUL' + '.' + new_template_file_extension) # Save the updated text to a new .TPL file with open(output_new_file_path, 'w') as file: file.write("\n".join(lines)) # Replace keys in current_parameter_values current_parameter_values = {parameter_par_truncated[key]: value for key, value in current_parameter_values.items() if key in parameter_par_truncated} minima_parameter_values = {parameter_par_truncated[key]: value for key, value in minima_parameter_values.items() if key in parameter_par_truncated} maxima_parameter_values = {parameter_par_truncated[key]: value for key, value in maxima_parameter_values.items() if key in parameter_par_truncated} # Update the values in parameters_grouped parameters_grouped = { key: ', '.join(parameter_par_truncated.get(param.strip(), param.strip()) for param in value.split(',')) for key, value in parameters_grouped.items() } print(f"Template file successfully created at: {output_new_file_path}") return {'parameters': current_parameter_values, 'minima_parameters': minima_parameter_values, 'maxima_parameters': maxima_parameter_values, 'parameters_grouped': parameters_grouped}, output_new_file_path except ValueError as ve: print(f"ValueError: {ve}") except FileNotFoundError as fe: print(f"FileNotFoundError: {fe}") except Exception as e: print(f"An unexpected error occurred: {e}")