Beispiel #1
0
def test_top_poses(n_poses, expected_energies):
    """
    Checks if data_handler extracts the correct number of top poses and associated metrics.
    Returns
    -------
        Folder with top poses.
    """
    output_folder = "tmp/top_poses"
    if os.path.exists(output_folder):
        shutil.rmtree(output_folder)

    analysis = Analysis(
        resname="LIG",
        chain="Z",
        simulation_output="../pele_platform/Examples/clustering",
        skip_initial_structures=False,
    )
    top_poses = analysis.generate_top_poses(output_folder, n_poses)
    top_poses_rounded = [round(pose, 3) for pose in top_poses]

    # Check if correct energy values were extracted
    assert len(top_poses) == n_poses
    for energy in expected_energies:
        assert energy in top_poses_rounded

    # Check if correct number of files was saved
    results = [
        os.path.basename(file)
        for file in glob.glob(os.path.join(output_folder, "*pdb"))
    ]
    assert len(results) == n_poses
Beispiel #2
0
def test_clustering_methods(method, bandwidth, n_clusters):
    """
    Checks if built-in clustering methods are producing expected number of clusters.

    Parameters
    ----------
    method : str
        Built-in clustering method, e.g. "dbscan".
    bandwidth : float
        Bandwidth for meanshift (or epsilon for DBSCAN).
    n_clusters : int
        Number of clusters for the Gaussian mixture model.

    Returns
    -------
        Folder with clusters, plots and report.
    """
    working_folder = "clustering_method"
    results = os.path.join(working_folder, "*pdb")

    if os.path.exists(working_folder):
        shutil.rmtree(working_folder)

    analysis = Analysis(
        resname="LIG",
        chain="Z",
        simulation_output="../pele_platform/Examples/clustering",
        skip_initial_structures=False)
    analysis.generate_clusters(working_folder,
                               method,
                               bandwidth=bandwidth,
                               analysis_nclust=n_clusters)
    assert len(glob.glob(results)) == n_clusters
Beispiel #3
0
def test_empty_reports_handling():
    """
    Checks if we handle reports with no accepted PELE steps to make sure the returned empty coordinates array doesn't
    cause any errors.
    """
    simulation_output = os.path.join(test_path,
                                     "analysis/data/empty_reports_output")
    analysis = Analysis(
        simulation_output=simulation_output,
        chain="Z",
        resname="LIG",
        skip_initial_structures=True,
    )
    analysis.generate(path="empty_reports")
Beispiel #4
0
    def _analysis(self):
        # TODO create a list of the libraries defined in the current input.yaml
        # Retrieve water indices to cluster, if running analysis only
        if self.parameters.only_analysis:
            self._extract_working_directory()
            for path in self.parameters.working_dir:
                if not os.path.exists(path):
                    if not os.path.exists(self.parameters.folder):
                        raise ce.MissingWorkingDir("Missing working_folder parameter. Please set the "
                                                   "path of the trajectories using the flag working_"
                                                   "folder in your input.yaml")
            self._prepare_parameters()
            self.parameters.water_ids_to_track = water.water_ids_from_conf(self.parameters.control_file)

        if self.parameters.args.analysis_to_point:
            self.parameters.analysis_to_point = self.parameters.args.analysis_to_point
            ana.main(
                path=self.parameters.folder,
                atom_coords=self.parameters.analysis_to_point,
                pattern=os.path.basename(self.parameters.system),
            )
        for path in self.parameters.working_dir:
            simulation_output = os.path.join(path, 'sampling_result')
            analysis_folder = os.path.join(path, "results")

            analysis = Analysis(
                resname="GRW",
                chain=self.parameters.chain,
                simulation_output=simulation_output,
                be_column=self.parameters.be_column,
                limit_column=self.parameters.limit_column,
                traj=self.parameters.traj_name,
                report=self.parameters.report_name,
                skip_initial_structures=not self.parameters.test,
                kde=self.parameters.kde,
                kde_structs=self.parameters.kde_structs,
                topology=self.parameters.topology,
                cpus=self.parameters.cpus,
                water_ids_to_track=self.parameters.water_ids_to_track,
            )
            analysis.generate(
                analysis_folder,
                clustering_type=self.parameters.clustering_method.lower(),
                bandwidth=self.parameters.bandwidth,
                analysis_nclust=self.parameters.analysis_nclust,
                max_top_clusters=self.parameters.max_top_clusters,
                top_clusters_criterion=self.parameters.top_clusters_criterion,
                min_population=self.parameters.min_population,
                representatives_criterion=self.parameters.cluster_representatives_criterion,
            )
Beispiel #5
0
    def _analysis(self):
        self.parameters.analysis_to_point = \
            self.parameters.args.analysis_to_point

        if self.parameters.analysis_to_point and self.parameters.folder:
            ana.main(path=self.parameters.folder,
                     atom_coords=self.parameters.analysis_to_point,
                     pattern=os.path.basename(self.parameters.system))

        # TODO create a list of the libraries defined in the current input.yaml
        from pele_platform.analysis import Analysis
        from glob import glob

        sim_directories = glob(
            os.path.splitext(self.parameters.system)[0] + '_processed_*' + '*')

        for sim_directory in sim_directories:
            simulation_output = os.path.join(sim_directory, 'sampling_result')

            # Only proceed if sampling_result folder exists
            if not os.path.isdir(simulation_output):
                continue

            analysis_folder = os.path.join(sim_directory, "results")

            analysis = Analysis(
                resname='GRW',
                chain=self.parameters.chain,
                simulation_output=simulation_output,
                be_column=self.parameters.be_column,
                limit_column=self.parameters.limit_column,
                traj=self.parameters.traj_name,
                report=self.parameters.report_name,
                skip_initial_structures=not self.parameters.test,
                kde=self.parameters.kde,
                kde_structs=self.parameters.kde_structs,
                topology=self.parameters.topology,
                cpus=self.parameters.cpus)
            analysis.generate(
                analysis_folder,
                clustering_type=self.parameters.clustering_method.lower(),
                bandwidth=self.parameters.bandwidth,
                analysis_nclust=self.parameters.analysis_nclust,
                max_top_clusters=self.parameters.max_top_clusters,
                top_clusters_criterion=self.parameters.top_clusters_criterion,
                min_population=self.parameters.min_population,
                representatives_criterion=self.parameters.
                cluster_representatives_criterion)
Beispiel #6
0
def test_residue_checker(path, traj, top):
    """
    Check, if we catch an error when the resname passed to Analysis doesn't exist in the output trajectories.

    Parameters
    -----------
    path : str
        Path to the simulation output folder.
    traj : str
        Trajectory type (as the user would set in the YAML), e.g. "trajectory.xtc".
    top : str
        Path to topology file.

    Raises
    --------
    ValueError if the residue name is not found in any of the trajectories.
    """
    simulation_output = os.path.join(test_path, path)
    topology = os.path.join(test_path, top) if top else None

    with pytest.raises(ValueError):
        analysis = Analysis(
            simulation_output=simulation_output,
            chain="Z",
            resname="STR",
            skip_initial_structures=True,
            traj=traj,
            topology=topology,
        )
Beispiel #7
0
def get_analysis(output, topology, traj):
    """
    Calls analysis fixture with the right arguments depending on the trajectory type.

    Parameters
    -----------
    output : str
        Path to simulation 'output' folder.
    topology : str
        Path to the topology file.
    traj : str
        Trajectory type: xtc or pdb.
    """
    traj = traj if traj else "pdb"
    trajectory = f"trajectory.{traj}"
    analysis = Analysis(
        resname="LIG",
        chain="Z",
        simulation_output=output,
        skip_initial_structures=False,
        topology=topology,
        water_ids_to_track=[("A", 2109), ("A", 2124)],
        traj=trajectory,
    )
    return analysis
Beispiel #8
0
def test_analysis_api():
    """
    Runs full analysis workflow (with GMM clustering).
    Returns
    -------
        Returns a directory with top_poses, clusters and plots.
    """
    working_folder = "full_analysis"
    output = "../pele_platform/Examples/clustering"
    n_clusts = 3

    analysis = Analysis(resname="LIG",
                        chain="Z",
                        simulation_output=output,
                        skip_initial_structures=False)
    analysis.generate(working_folder,
                      "gaussianmixture",
                      analysis_nclust=n_clusts)

    # Check if reports exist
    assert os.path.exists(os.path.join(working_folder, "data.csv"))
    assert os.path.exists(os.path.join(working_folder, "summary.pdf"))

    # Check plots
    plots = glob.glob(os.path.join(working_folder, "plots", "*png"))
    assert len(plots) == 2

    # Check top poses
    top_poses = glob.glob(os.path.join(working_folder, "top_poses", "*pdb"))
    assert len(top_poses) == 7

    # Check clusters
    clusters = glob.glob(os.path.join(working_folder, "clusters", "*pdb"))
    assert len(clusters) == n_clusts

    # Check if data.csv exists and is not empty
    data_csv = os.path.join(working_folder, "data.csv")
    assert os.path.exists(data_csv)

    with open(data_csv, "r") as file:
        lines = file.readlines()
        assert len(lines) == 8
        assert lines[
            0] == "Step,numberOfAcceptedPeleSteps,currentEnergy,Binding Energy,sasaLig,epoch,trajectory,Cluster\n"
Beispiel #9
0
def test_frag_API_analysis(yaml_file, traj, topology):
    """
    Runs frag simulation (both XTC and PDB) and checks, if it's possible to run Analysis via API.

    Parameters
    -----------
    yaml_file : str
        Base name of the input.yaml file in Examples/frag.
    traj : str
        Indicate if running "pdb" or "xtc".
    topology : str
        Path to the topology file, if running XTC simulation, otherwise None
    """
    # Run frag simulation
    yaml_file = os.path.join(test_path, "frag", yaml_file)
    job = main.run_platform_from_yaml(yaml_file)

    # Run analysis
    frag_folder = "1w7h_preparation_structure_2w_processed_frag_aminoC1N1"
    output = os.path.join(frag_folder, "sampling_result")
    analysis_output = f"analysis_{traj}"
    traj = f"trajectory.{traj}"

    if topology:
        topology = os.path.join(frag_folder, topology)

    analysis = Analysis(simulation_output=output,
                        resname="GRW",
                        chain="L",
                        traj=traj,
                        topology=topology)
    analysis.generate(analysis_output)

    # Check output
    assert len(glob.glob(os.path.join(analysis_output, "plots", "*png"))) > 0
    assert len(
        glob.glob(os.path.join(analysis_output, "clusters",
                               "cluster*pdb"))) > 0

    shutil.rmtree(frag_folder, ignore_errors=True)
Beispiel #10
0
def test_check_existing_directory(generate_folders):
    """
    Checks if tester of existing dir

    Parameters
    ----------
    generate_folders : pytest.fixture
        Pytest fixture that generates "results" folders for testing
    """
    new_path = Analysis._check_existing_directory("results")
    assert new_path == "results_3"

    folders = glob.glob("results*")
    check_remove_folder(*folders)
Beispiel #11
0
def analysis():
    """
    Creates Analysis object to use in other tests.
    Returns
    -------
        Analysis object.
    """
    output = "../pele_platform/Examples/clustering"

    analysis = Analysis(resname="LIG",
                        chain="Z",
                        simulation_output=output,
                        skip_initial_structures=False)

    return analysis
Beispiel #12
0
def run_adaptive(args: YamlParser):
    """
    Main function to prepare and launch the simulation.

    1) Create Parameters - variables, folders, logger...
    2) Prepare ligand and receptor
    3) Launch simulation
    4) Analyse simulation
    """
    builder = ParametersBuilder()
    parameters = builder.build_adaptive_variables(args)
    parameters.create_files_and_folders()
    shutil.copy(args.yamlfile, parameters.pele_dir)
    missing_residues = []

    if parameters.adaptive_restart and not parameters.only_analysis:
        with helpers.cd(parameters.pele_dir):
            adaptiveSampling.main(parameters.ad_ex_temp)
            parameters.logger.info("Simulation run successfully (:\n\n")
        args.adaptive_restart = False

    elif not parameters.only_analysis and not parameters.restart:
        parameters.logger.info(
            "System: {}; Platform Functionality: {}\n\n".format(
                parameters.residue, parameters.software))

        pdb_checker.PDBChecker(parameters.system).check_negative_residues()

        # Create inputs directory
        if not os.path.exists(parameters.inputs_dir):
            os.mkdir(parameters.inputs_dir)

        if parameters.perturbation:
            syst = sp.SystemBuilder.build_system(
                parameters.system,
                args.mae_lig,
                args.residue,
                parameters.pele_dir,
                inputs_dir=parameters.inputs_dir)
        else:
            syst = sp.SystemBuilder(parameters.system,
                                    None,
                                    None,
                                    parameters.pele_dir,
                                    inputs_dir=parameters.inputs_dir)

        parameters.logger.info("Prepare complex {}".format(syst.system))

        # If user overrides 'system' with 'input'
        if parameters.input:
            parameters.inputs_simulation = []

            for input in parameters.input:
                input_path = os.path.join(parameters.inputs_dir,
                                          os.path.basename(input))
                shutil.copy(input, input_path)

                if parameters.no_ppp:
                    input_proc = input_path
                else:
                    input_proc, missing_residues, _, _, _ = ppp.main(
                        input_path,
                        parameters.
                        inputs_dir,  # to ensure it goes to pele_dir/inputs, not pele_dir
                        output_pdb=[
                            "",
                        ],
                        charge_terminals=args.charge_ter,
                        no_gaps_ter=args.gaps_ter,
                        constrain_smiles=None,
                        ligand_pdb=parameters.ligand_ref)
                input_proc = os.path.basename(input_proc)
                input_proc = os.path.join(parameters.inputs_dir, input_proc)
                parameters.inputs_simulation.append(input_proc)
            parameters.adap_ex_input = ", ".join([
                '"' + input + '"' for input in parameters.inputs_simulation
            ]).strip('"')

        # If randomization in necessary (PPI, site_finder, global exploration)...
        elif args.full or args.randomize or args.ppi or args.site_finder:
            ligand_positions, box_radius, box_center = rd.randomize_starting_position(
                parameters, args.box_center, args.box_radius)

            if parameters.no_ppp:
                receptor = syst.system
            else:
                receptor, missing_residues, _, _, _ = ppp.main(
                    syst.system,
                    parameters.
                    inputs_dir,  # to ensure it goes to pele_dir/input, not pele_dir
                    output_pdb=[
                        "",
                    ],
                    charge_terminals=args.charge_ter,
                    no_gaps_ter=args.gaps_ter,
                    constrain_smiles=None,
                    ligand_pdb=parameters.ligand_ref)

            inputs = rd.join(receptor,
                             ligand_positions,
                             parameters.residue,
                             output_folder=parameters.inputs_dir)

            parameters.input = [
                os.path.join(parameters.inputs_dir, inp) for inp in inputs
            ]

            if args.gpcr_orth or args.out_in:
                randomization_box_radius, randomization_box_center = rd.set_box(
                    args.final_site if args.final_site else
                    args.orthosteric_site, ligand_positions, parameters.system)

                if not args.box_center:
                    parameters.box_center = randomization_box_center
                if not args.box_radius:
                    parameters.box_radius = randomization_box_radius

            else:
                parameters.box_center = box_center
                parameters.box_radius = box_radius

            parameters.adap_ex_input = ", ".join(
                ['"' + input + '"' for input in parameters.input]).strip('"')
            hp.silentremove(ligand_positions)

        # Prepare System
        if parameters.no_ppp or parameters.input:  # No need to run system through PPP, if we already preprocessed
            # parameters.input
            if parameters.input:
                # If we have more than one input
                for input in parameters.input:
                    try:
                        shutil.copy(input, parameters.inputs_dir)
                    except shutil.SameFileError:  # systems that go through randomization are already moved
                        pass
            else:
                shutil.copy(parameters.system, parameters.inputs_dir)
        else:
            parameters.nonstandard.extend(hp.find_nonstd_residue(syst.system))
            parameters.system, missing_residues, _, _, _ = ppp.main(
                syst.system,
                parameters.inputs_dir,
                output_pdb=[
                    "",
                ],
                charge_terminals=args.charge_ter,
                no_gaps_ter=args.gaps_ter,
                mid_chain_nonstd_residue=parameters.nonstandard,
                skip=parameters.skip_prep,
                back_constr=parameters.ca_constr,
                constrain_smiles=None,
                ligand_pdb=parameters.ligand_ref,
                ca_interval=parameters.ca_interval)

        parameters.constraints = alpha_constraints.retrieve_constraints(
            parameters.system,
            interval=parameters.ca_interval,
            back_constr=parameters.ca_constr,
            ter_constr=parameters.terminal_constr)

        # Metal constraints
        if not args.no_metal_constraints:
            metal_constraints, parameters.external_constraints = mc.main(
                args.external_constraints,
                os.path.join(
                    parameters.inputs_dir,
                    parameters.adap_ex_input.split(",")[0].strip().strip('"')),
                syst.system,
                permissive=parameters.permissive_metal_constr,
                all_metals=args.constrain_all_metals,
                external=parameters.external_constraints,
                logger=parameters.logger)

            parameters.external_constraints = hp.retrieve_constraints_for_pele(
                parameters.external_constraints, parameters.system)

            metal_constraints_json = hp.retrieve_constraints_for_pele(
                metal_constraints,
                os.path.join(
                    parameters.inputs_dir,
                    parameters.adap_ex_input.split(",")[0].strip().strip('"')))

            parameters.external_constraints.extend(metal_constraints_json)

        else:
            parameters.external_constraints = hp.retrieve_constraints_for_pele(
                parameters.external_constraints, parameters.system)

        # Keep JSON ordered by having first title and then constraints
        if parameters.external_constraints:
            parameters.constraints = (parameters.constraints[0:1] +
                                      parameters.external_constraints +
                                      parameters.constraints[1:])
        if parameters.remove_constraints:
            parameters.constraints = ""

        parameters.logger.info(f"Complex {parameters.system} prepared\n\n")

        # Ligand/metal and solvent parameters
        if (parameters.perturbation or
                parameters.sidechain_perturbation) and parameters.use_peleffy:
            ligand_parametrizer = parametrizer.Parametrizer.from_parameters(
                parameters)
            ligand_parametrizer.parametrize_ligands_from(
                pdb_file=syst.system, ppp_file=parameters.system)

        elif (parameters.perturbation or parameters.sidechain_perturbation
              ) and not parameters.use_peleffy:
            # Parametrize the ligand
            ligand_params = lg.LigandParametrization(parameters)
            ligand_params.generate()

            # Parametrize missing residues identified by PPP
            for res, __, _ in missing_residues:
                if res != args.residue and res not in parameters.skip_ligand_prep:
                    parameters.logger.info(
                        "Creating template for residue {}".format(res))
                    with hp.cd(parameters.pele_dir):
                        mr.create_template(parameters, res)
                    parameters.logger.info(
                        "Template {}z created\n\n".format(res))

        # Covalent residue parametrization should not run in refinement simulation
        if parameters.covalent_residue and os.path.basename(
                parameters.pele_dir) != "2_refinement":
            parametrizer.parametrize_covalent_residue(
                parameters.pele_data,
                parameters.pele_dir,
                parameters.gridres,
                parameters.residue_type,
                parameters.residue,
                ppp_system=parameters.system)

        if parameters.ligand_conformations:
            ligand_conformations.LigandConformations(
                path=parameters.ligand_conformations,
                system=parameters.system,
                resname=parameters.residue,
                forcefield=parameters.forcefield,
                pele_dir=parameters.pele_dir).generate()

        # Create simulation box, if performing perturbation
        if parameters.perturbation and parameters.box:
            box = bx.BoxSetter(parameters.box_center, parameters.box_radius,
                               parameters.ligand_ref, parameters.logger)
            parameters.box = box.generate_json()
        else:
            parameters.box = ""

        # Solvent parameters
        solvent = sv.ImplicitSolvent(
            parameters.solvent,
            parameters.obc_tmp,
            parameters.template_folder,
            parameters.obc_file,
            parameters.logger,
        )
        solvent.generate()

        # Build PCA
        if parameters.pca_traj:
            pca_obj = pca.PCA(parameters.pca_traj, parameters.pele_dir)
            parameters.pca = pca_obj.generate(parameters.logger)

        # Core constraints based on SMILES string
        if parameters.constrain_core:
            smiles_input_pdb = os.path.join(
                parameters.inputs_dir,
                parameters.adap_ex_input.split(",")[0])
            smiles = smiles_constraints.SmilesConstraints(
                smiles_input_pdb, parameters.constrain_core,
                parameters.residue, parameters.chain,
                parameters.constrain_core_spring)
            smi_constraint = smiles.run()
            parameters.constraints = (parameters.constraints[0:1] +
                                      smi_constraint +
                                      parameters.constraints[1:])

        # Waters
        input_waters = [
            input.strip().strip('"')
            for input in parameters.adap_ex_input.split(",")
        ]
        input_waters = [
            os.path.join(parameters.inputs_dir, inp) for inp in input_waters
        ]
        water_obj = wt.WaterIncluder(
            input_waters,
            parameters.n_waters,
            user_waters=parameters.waters,
            ligand_perturbation_params=parameters.parameters,
            water_center=args.water_center,
            water_radius=parameters.water_radius,
            allow_empty_selectors=parameters.allow_empty_selectors,
            water_temp=parameters.water_temp,
            water_trials=parameters.water_trials,
            water_overlap=parameters.water_overlap,
            water_constr=parameters.water_constr,
            test=parameters.test,
            water_freq=parameters.water_freq,
            ligand_residue=parameters.residue)
        water_obj.run()
        parameters.parameters = water_obj.ligand_perturbation_params
        parameters.water_ids_to_track = water_obj.water_ids_to_track

        # Check if atoms need mapping due to preprocessing
        args = AtomMapper(args, parameters, syst.system).run()

        # Metrics builder - builds JSON strings for PELE to be able to
        # track atom distances, RMSD, etc.
        metrics = mt.MetricBuilder()
        parameters.metrics = (metrics.distance_to_atom_json(
            os.path.join(
                parameters.inputs_dir,
                parameters.adap_ex_input.split(",")[0].strip().strip('"'),
            ),
            args.atom_dist,
        ) if args.atom_dist else "")
        parameters.native = (metrics.rmsd_to_json(
            args.native, parameters.chain) if args.native else "")

        parameters.local_nonbonding_energy = metrics.local_nonbonding_energy_json(
            parameters.covalent_residue, parameters.nonbonding_radius)

        # metal polarisation
        if parameters.polarize_metals:
            mp.change_metal_charges(
                parameters.template_folder,
                parameters.forcefield,
                parameters.polarization_factor,
                parameters.system,
            )

        # Predict cluster values in a short equilibration
        if parameters.cluster_conditions == "auto":
            preequilibration = PreEquilibrator(args, parameters)
            parameters.cluster_conditions = preequilibration.run()

        # Point adaptive.conf to input dir
        parameters.adap_ex_input = os.path.join(parameters.inputs_dir,
                                                parameters.adap_ex_input)

        # Fill in simulation templates
        adaptive = ad.SimulationBuilder(parameters.ad_ex_temp,
                                        parameters.pele_exit_temp,
                                        parameters.topology)
        adaptive.generate_inputs(parameters, water_obj)

        # Run simulation only if we are not in debug mode
        if not parameters.debug:
            parameters.logger.info("Running Simulation")
            adaptive.run()
            parameters.logger.info("Simulation run successfully (:\n\n")

    elif parameters.restart and not parameters.only_analysis:
        # Start simulation from scratch (unlike adaptive_restart) but use files created in debug mode
        parameters.logger.info(
            f"Launching simulation from {parameters.pele_dir}")
        adaptive = ad.SimulationBuilder(parameters.ad_ex_temp,
                                        parameters.pele_exit_temp,
                                        parameters.topology)
        adaptive.run()
        parameters.logger.info("Simulation run successfully (:\n\n")

    # Run analysis
    if parameters.analyse and not parameters.debug:
        from pele_platform.analysis import Analysis

        # Retrieve water IDs to track from existing pele.conf, if running analysis only
        if parameters.only_analysis:
            parameters.water_ids_to_track = wt.water_ids_from_conf(
                parameters.pele_temp)

        analysis_folder = os.path.join(parameters.pele_dir, "results")

        analysis = Analysis.from_parameters(parameters)
        analysis.generate(
            analysis_folder,
            clustering_type=parameters.clustering_method.lower(),
            bandwidth=parameters.bandwidth,
            analysis_nclust=parameters.analysis_nclust,
            max_top_clusters=parameters.max_top_clusters,
            min_population=parameters.min_population,
            max_top_poses=parameters.max_top_poses,
            top_clusters_criterion=parameters.top_clusters_criterion,
            representatives_criterion=parameters.
            cluster_representatives_criterion)

    return parameters
Beispiel #13
0
def run_adaptive(args):
    """
    Main function to prepare and launch the simulation.

    1) Create EnviroBuilder - variables, folders, logger...
    2) Prepare ligand and receptor
    3) Launch simulation
    4) Analyse simulation
    """
    builder = ParametersBuilder()
    parameters = builder.build_adaptive_variables(args)
    parameters.create_files_and_folders()
    shutil.copy(args.yamlfile, parameters.pele_dir)

    if parameters.adaptive_restart and not parameters.only_analysis:
        with helpers.cd(parameters.pele_dir):
            adaptiveSampling.main(parameters.ad_ex_temp)
            parameters.logger.info("Simulation run successfully (:\n\n")

    elif not parameters.only_analysis:
        parameters.logger.info(
            "System: {}; Platform Functionality: {}\n\n".format(
                parameters.residue, parameters.software))

        # Create inputs directory
        if not os.path.exists(parameters.inputs_dir):
            os.mkdir(parameters.inputs_dir)

        if parameters.perturbation:
            syst = sp.SystemBuilder.build_system(
                parameters.system,
                args.mae_lig,
                args.residue,
                parameters.pele_dir,
                inputs_dir=parameters.inputs_dir,
            )
        else:
            syst = sp.SystemBuilder(
                parameters.system,
                None,
                None,
                parameters.pele_dir,
                inputs_dir=parameters.inputs_dir,
            )

        parameters.logger.info("Prepare complex {}".format(syst.system))

        # If user overrides 'system' with 'input'
        if parameters.input:
            parameters.inputs_simulation = []

            for input in parameters.input:
                input_path = os.path.join(parameters.inputs_dir,
                                          os.path.basename(input))
                shutil.copy(input, input_path)

                if parameters.no_ppp:
                    input_proc = input_path
                else:
                    input_proc = os.path.basename(
                        ppp.main(
                            input_path,
                            parameters.
                            inputs_dir,  # to ensure it goes to pele_dir/inputs, not pele_dir
                            output_pdb=[
                                "",
                            ],
                            charge_terminals=args.charge_ter,
                            no_gaps_ter=args.gaps_ter,
                            constrain_smiles=None,
                            ligand_pdb=parameters.ligand_ref,
                        )[0])
                input_proc = os.path.join(parameters.inputs_dir, input_proc)
                parameters.inputs_simulation.append(input_proc)
            parameters.adap_ex_input = ", ".join([
                '"' + input + '"' for input in parameters.inputs_simulation
            ]).strip('"')

        # If randomization in necessary (PPI, site_finder, global exploration)...
        elif args.full or args.randomize or args.ppi:
            ligand_positions, box_radius, box_center = rd.randomize_starting_position(
                parameters.ligand_ref,
                parameters.receptor,
                outputfolder=parameters.inputs_dir,
                nposes=parameters.poses,
                test=parameters.test,
                user_center=parameters.center_of_interface,
                logger=parameters.logger,
            )
            if not args.gpcr_orth:
                parameters.box_center = box_center
                parameters.box_radius = box_radius
            if parameters.no_ppp:
                receptor = syst.system
            else:
                receptor = ppp.main(
                    syst.system,
                    parameters.
                    inputs_dir,  # to ensure it goes to pele_dir/input, not pele_dir
                    output_pdb=[
                        "",
                    ],
                    charge_terminals=args.charge_ter,
                    no_gaps_ter=args.gaps_ter,
                    constrain_smiles=None,
                    ligand_pdb=parameters.ligand_ref,
                )[0]
            inputs = rd.join(
                receptor,
                ligand_positions,
                parameters.residue,
                output_folder=parameters.inputs_dir,
            )

            inputs = [
                os.path.join(parameters.inputs_dir, inp) for inp in inputs
            ]

            parameters.adap_ex_input = ", ".join(
                ['"' + input + '"' for input in inputs]).strip('"')
            hp.silentremove(ligand_positions)

        # Prepare System
        if (
                parameters.no_ppp or parameters.input
        ):  # No need to run system through PPP, if we already preprocessed parameters.input
            missing_residues = []
            if parameters.input:
                # If we have more than one input
                for input in parameters.input:
                    shutil.copy(input, parameters.inputs_dir)
            else:
                shutil.copy(parameters.system, parameters.inputs_dir)
        else:
            parameters.nonstandard.extend(hp.find_nonstd_residue(syst.system))
            parameters.system, missing_residues, _, _, _ = ppp.main(
                syst.system,
                parameters.inputs_dir,
                output_pdb=[
                    "",
                ],
                charge_terminals=args.charge_ter,
                no_gaps_ter=args.gaps_ter,
                mid_chain_nonstd_residue=parameters.nonstandard,
                skip=parameters.skip_prep,
                back_constr=parameters.ca_constr,
                constrain_smiles=None,
                ligand_pdb=parameters.ligand_ref,
                ca_interval=parameters.ca_interval,
            )

        parameters.constraints = alpha_constraints.retrieve_constraints(
            parameters.system,
            interval=parameters.ca_interval,
            back_constr=parameters.ca_constr,
            ter_constr=parameters.terminal_constr,
        )

        # Metal constraints
        if not args.no_metal_constraints:
            metal_constraints, parameters.external_constraints = mc.main(
                args.external_constraints,
                os.path.join(
                    parameters.inputs_dir,
                    parameters.adap_ex_input.split(",")[0].strip().strip('"'),
                ),
                syst.system,
                permissive=parameters.permissive_metal_constr,
                all_metals=args.constrain_all_metals,
                external=parameters.external_constraints,
                logger=parameters.logger,
            )
            parameters.external_constraints = hp.retrieve_constraints_for_pele(
                parameters.external_constraints, parameters.system)

            metal_constraints_json = hp.retrieve_constraints_for_pele(
                metal_constraints,
                os.path.join(
                    parameters.inputs_dir,
                    parameters.adap_ex_input.split(",")[0].strip().strip('"'),
                ),
            )
            parameters.external_constraints.extend(metal_constraints_json)
        else:
            parameters.external_constraints = hp.retrieve_constraints_for_pele(
                parameters.external_constraints, parameters.system)

        # Keep JSON ordered by having first title and then constraints
        if parameters.external_constraints:
            parameters.constraints = (parameters.constraints[0:1] +
                                      parameters.external_constraints +
                                      parameters.constraints[1:])
        if parameters.remove_constraints:
            parameters.constraints = ""
        parameters.logger.info("Complex {} prepared\n\n".format(
            parameters.system))

        # Ligand parameters and simulation box
        if parameters.perturbation:
            ligand_params = lg.LigandParametrization(parameters)
            ligand_params.generate()
            box = bx.BoxSetter(
                parameters.box_center,
                parameters.box_radius,
                parameters.ligand_ref,
                parameters.logger,
            )
            parameters.box = box.generate_json()
        else:
            parameters.box = ""

        # Parametrize missing residues
        for res, __, _ in missing_residues:
            if res != args.residue and res not in parameters.skip_ligand_prep:
                parameters.logger.info(
                    "Creating template for residue {}".format(res))
                with hp.cd(parameters.pele_dir):
                    mr.create_template(parameters, res)
                parameters.logger.info("Template {}z created\n\n".format(res))

        # Solvent parameters
        solvent = sv.ImplicitSolvent(
            parameters.solvent,
            parameters.obc_tmp,
            parameters.template_folder,
            parameters.obc_file,
            parameters.logger,
        )
        solvent.generate()

        # Build PCA
        if parameters.pca_traj:
            pca_obj = pca.PCA(parameters.pca_traj, parameters.pele_dir)
            parameters.pca = pca_obj.generate(parameters.logger)

        # Core constraints based on SMILES string
        if parameters.constrain_core:
            smiles_input_pdb = os.path.join(
                parameters.inputs_dir,
                parameters.adap_ex_input.split(",")[0])
            smiles = smiles_constraints.SmilesConstraints(
                smiles_input_pdb,
                parameters.constrain_core,
                parameters.residue,
                parameters.chain,
                parameters.constrain_core_spring,
            )
            smi_constraint = smiles.run()
            parameters.constraints = (parameters.constraints[0:1] +
                                      smi_constraint +
                                      parameters.constraints[1:])

        # Waters
        input_waters = [
            input.strip().strip('"')
            for input in parameters.adap_ex_input.split(",")
        ]
        input_waters = [
            os.path.join(parameters.inputs_dir, inp) for inp in input_waters
        ]
        water_obj = wt.WaterIncluder(
            input_waters,
            parameters.n_waters,
            user_waters=parameters.waters,
            ligand_perturbation_params=parameters.parameters,
            water_center=args.water_center,
            water_radius=parameters.water_radius,
            allow_empty_selectors=parameters.allow_empty_selectors,
            water_temp=parameters.water_temp,
            water_trials=parameters.water_trials,
            water_overlap=parameters.water_overlap,
            water_constr=parameters.water_constr,
            test=parameters.test,
            water_freq=parameters.water_freq,
            ligand_residue=parameters.residue,
        )
        water_obj.run()
        parameters.parameters = water_obj.ligand_perturbation_params

        # Check if atoms need mapping due to preprocessing
        args = AtomMapper(args, parameters, syst.system).run()

        # Metrics builder - builds JSON strings for PELE to be able to track atom distances, RMSD, etc.
        metrics = mt.MetricBuilder()
        parameters.metrics = (metrics.distance_to_atom_json(
            os.path.join(
                parameters.inputs_dir,
                parameters.adap_ex_input.split(",")[0].strip().strip('"'),
            ),
            args.atom_dist,
        ) if args.atom_dist else "")
        parameters.native = (metrics.rsmd_to_json(
            args.native, parameters.chain) if args.native else "")

        # interaction restrictions
        # TODO this is not the place to initialize parameters for the interaction restrictions
        if args.interaction_restrictions:
            interaction_restrictions = ir.InteractionRestrictionsBuilder()
            interaction_restrictions.parse_interaction_restrictions(
                parameters.system, args.interaction_restrictions)
            parameters.met_interaction_restrictions = (
                interaction_restrictions.metrics_to_json())
            parameters.interaction_restrictions = (
                interaction_restrictions.conditions_to_json())
        else:
            parameters.met_interaction_restrictions = ""
            parameters.interaction_restrictions = ""

        # metal polarisation
        if parameters.polarize_metals:
            mp.change_metal_charges(
                parameters.template_folder,
                parameters.forcefield,
                parameters.polarization_factor,
                parameters.system,
            )

        # Point adaptive.conf to input dir
        parameters.adap_ex_input = os.path.join(parameters.inputs_dir,
                                                parameters.adap_ex_input)

        # Fill in simulation templates
        adaptive = ad.SimulationBuilder(parameters.ad_ex_temp,
                                        parameters.pele_exit_temp,
                                        parameters.topology)
        adaptive.generate_inputs(parameters, water_obj)

        # Run simulation only if we are not in debug mode
        if not parameters.debug:
            parameters.logger.info("Running Simulation")
            adaptive.run()
            parameters.logger.info("Simulation run successfully (:\n\n")

    # Run analysis
    if parameters.analyse and not parameters.debug:
        from pele_platform.analysis import Analysis

        analysis_folder = os.path.join(parameters.pele_dir, "results")

        analysis = Analysis.from_parameters(parameters)
        analysis.generate(analysis_folder,
                          clustering_type=parameters.clustering_method.lower(),
                          bandwidth=parameters.bandwidth,
                          analysis_nclust=parameters.analysis_nclust,
                          max_top_clusters=parameters.max_top_clusters,
                          min_population=parameters.min_population)

    return parameters