text: """
  This module holds the classes and methods to build and manage the parameters
  that are required by the PELE Platform to run the different workflows.
  """
  
  __all__ = ["ParametersBuilder", "Parameters"]
  
  
  from pele_platform.Utilities.Parameters.SimulationParams import \
      simulation_params
  from pele_platform.Utilities.Parameters.SimulationFolders import \
      simulation_folders
  
  
  class ParametersBuilder(object):
      """
      It builds a Parameters instance and it creates the required folders and
      files
      """
  
      def __init__(self):
          """
          It initializes a ParametersBuilder object.
          """
          self._parameters = None
          self._initialized = False
  
      def build_adaptive_variables(self, args):
          """
          It builds the parameters for adaptive, according to the arguments
          that are supplied, and returns the corresponding Parameters
          instance.
  
          Parameters
          ----------
          args : a YamlParser object
              The YamlParser object containing the input parameters chosen
              by the user
  
          Returns
          -------
          parameters : a Parameters object
              The Parameters object containing the parameters for PELE
          """
          import os
  
          from pele_platform.features import adaptive
          from pele_platform.Utilities.Helpers import helpers
  
          # Define main PELE directory
          main_dir = os.path.abspath("{}_Pele".format(args.residue))
  
          # Set the PELE directory
          # In case that folder is not set by the user, we will try to suggest
          # the best candidate considering whether we want to restart a previous
          # simulation or we want to run a new one from scratch.
          if not args.folder:
              # If the simulation is being restarted (after debug), adaptive_restarted (from last epoch)
              # or if we're running only_analysis we need to retrieve the LAST pele_dir. Otherwise create a new one
              # with a new index.
              if args.restart or args.adaptive_restart or args.only_analysis:
                  pele_dir = helpers.get_latest_peledir(main_dir)
              else:
                  pele_dir = helpers.get_next_peledir(main_dir)
  
          # In case that the user has specified the output folder, we will
          # use it, regardless it already exists.
          else:
              pele_dir = os.path.abspath(args.folder)
  
          if (args.restart or args.adaptive_restart or args.only_analysis) and not os.path.exists(pele_dir):
              raise OSError(f"Directory {pele_dir} was not found. Please ensure you set the correct path to the top level"
                            f" directory, e.g. 'LIG_Pele' using the 'working_folder' flag when restarting or analysing "
                            f"the simulation.")
  
          # Retrieve the specific args for adaptive
          specific_args = adaptive.retrieve_software_settings(args, pele_dir)
  
          # Add pele_dir
          specific_args['pele_dir'] = pele_dir
  
          # Initialize Parameters object
          self._parameters = Parameters(args, specific_args)
          self._initialized = True
  
          # Set software
          self.parameters.software = "Adaptive"
  
          return self.parameters
  
      def build_frag_variables(self, args):
          """
          It builds the parameters for frag, according to the arguments
          that are supplied, and returns the corresponding Parameters
          instance.
  
          Parameters
          ----------
          args : a YamlParser object
              The YamlParser object containing the input parameters chosen
              by the user
  
          Returns
          -------
          parameters : a Parameters object
              The Parameters object containing the parameters for PELE
          """
          from pele_platform.features import frag
          from pele_platform.Frag.parameters import FragWaterParams
          from pele_platform.Frag.parameters import FragInputFiles
          from pele_platform.Frag.parameters import FragSimulationParameters
          from pele_platform.Frag.parameters import FragMetrics
          from pele_platform.Frag.parameters import FragOptionalParameters
  
          # Retrieve the specific args for FragPELE
          specific_args = frag.retrieve_software_settings(args)
  
          # Initialize Parameters object
          self._parameters = Parameters(args, specific_args,
                                        initialize_simulation_paths=False)
          self._initialized = True
  
          # Initialize water parameters for FragPELE
          FragWaterParams(self.parameters, args)
  
          # Initialize file parameters for FragPELE
          FragInputFiles(self.parameters, args)
  
          # Initialize simulation parameters for FragPELE
          FragSimulationParameters(self.parameters, args)
  
          # Initialize metrics parameters for FragPELE
          FragMetrics(self.parameters, args)
  
          # Initialize optional parameters for FragPELE
          FragOptionalParameters(self.parameters, args)
  
          # Keep initial arguments
          self.parameters.args = args
  
          # Create logger
          self.parameters.create_logger(".")
  
          # Set software
          self.parameters.software = "Frag"
  
          return self.parameters
  
      @property
      def initialized(self):
          """
          It returns the initialization state of the builder. If this builder
          has already built a Parameters object before, it will return a True.
          Otherwise, it will return a False.
  
          Returns
          -------
          initialized : bool
              Whether this ParametersBuilder has already been used to build
              a Parameters object or not
          """
          return self._initialized
  
      @property
      def parameters(self):
          """
          It returns the Parameters object that has been built by the current
          ParametersBuilder instance, if any. In case that it has not been built
          yet (ParametersBuilder not initialized), it will return None.
  
          Returns
          -------
          _parameters : a Parameters object
              The Parameters object containing the right parameters according
              to the input given by the user
          """
          return self._parameters
  
  
  class Parameters(simulation_params.SimulationParams,
                   simulation_folders.SimulationPaths):
      """
      Base parameters class where the PELE Platform parameters are stored
      and manipulated.
  
      .. todo ::
         * This class should be serializable. For example, we should be able to
           represent it as a json format at any time. We need to implement
           an abstract class for this purpose, something like in:
           https://github.com/openforcefield/openff-toolkit/blob/master/openff/toolkit/utils/serialization.py#L25
  
          * The args parameter that is required must be refactored. Among other
            things, it must support a Python API and its initialization and
            modification must be as easy and straightforward as possible.
  
         * Consider moving the functionality about the creation of files
           and folders outside this method.
      """
  
      def __init__(self, args, specific_args=None,
                   initialize_simulation_params=True,
                   initialize_simulation_paths=True):
          """
          It initializes a Parameters object.
  
          .. todo ::
             * We need to refactor the inheritance from
                - simulation_params.SimulationParams and
                - simulation_folders.SimulationPaths
               since the parameters initialization is currently very
               complex and confusing.
  
          Parameters
          ----------
          args : a YamlParser object
              The YamlParser object containing the input parameters chosen
              by the user
          specific_args : dict
              The dictionary containing the specific parameters for this
              Parameter object
          initialize_simulation_params : bool
              Whether to initialize the simulation parameters or not. Default
              is True
          initialize_simulation_paths : bool
              Whether to initialize the simulation paths or not. Default
              is True
          """
          # CA interval is first initialized to None
          self.ca_interval = None
  
          # If specific_args is not defined, assign and empty dictionary
          if specific_args is None:
              specific_args = dict()
  
          # Set specific parameters, they need to be set before initializing
          # the rest
          for key, value in specific_args.items():
              setattr(self, key, value)
  
          # Initialize the parameters from parent classes
          if initialize_simulation_params:
              simulation_params.SimulationParams.__init__(self, args)
          if initialize_simulation_paths:
              simulation_folders.SimulationPaths.__init__(self, args)
  
          # We need to set the specific arguments again
          for key, value in specific_args.items():
              setattr(self, key, value)
  
      def create_files_and_folders(self):
          if not self.adaptive_restart and not self.only_analysis and not self.restart:
              self.create_folders()
              self.create_files()
          self.create_logger()
  
      def create_folders(self):
          """
              Create pele folders
          """
          from pele_platform.Utilities.Helpers import helpers
  
          for folder in self.folders:
              helpers.create_dir(self.pele_dir, folder)
  
      def create_files(self):
          """
              Copy templates
          """
          import os
          import shutil
  
          # Actions
          for file, destination_name in zip(self.files, self.file_names):
              shutil.copy(file, os.path.join(self.pele_dir, destination_name))
  
      def create_logger(self, directory=None):
          """
          Given a directory, it initiates a logger in that place.
  
          Parameters
          ----------
          directory : str
              The directory where the logger will be stored. Default uses the
              main PELE directory
          """
          import os
          import logging
  
          directory = directory if directory else self.pele_dir
          log_name = os.path.join(directory, "{}.log".format(self.residue))
          self.logger = logging.getLogger(__name__)
          self.logger.setLevel(logging.INFO)
          self.logger.propagate = False
          formatter = logging.Formatter("%(asctime)s:%(levelname)s:%(message)s")
          if not self.adaptive_restart:
              file_handler = logging.FileHandler(log_name, mode='w')
          else:
              file_handler = logging.FileHandler(log_name, mode='a')
          file_handler.setFormatter(formatter)
          self.logger.addHandler(file_handler)
  
      def to_json(self, indent=None):
          """
          Return a JSON serialized representation.
          Specification: https://www.json.org/
  
      .. todo ::
         * Consider moving this method to a general abstract class to
           serialize classes.
  
          Parameters
          ----------
          indent : int, optional, default=None
              If not None, will pretty-print with specified number of spaces
              for indentation
  
          Returns
          -------
          serialized : str
              A JSON serialized representation of the object
          """
          import json
  
          d = self.to_dict()
  
          return json.dumps(d, indent=indent)
  
      def to_dict(self):
          """
          Return a dictionary representation of the Parameters object.
  
          Returns
          -------
          parameters_dict : an OrderedDict object
              The dictionary representation of the current Parameters object.
          """
          from collections import OrderedDict
  
          parameters_dict = OrderedDict()
  
          for attribute, value in self.__dict__.items():
              # Skip special and private attributes
              if attribute.startswith('__') and attribute.endswith('__'):
                  continue
  
              parameters_dict[attribute] = value
  
          return parameters_dict
  