docs: def infer(args):
      """
      Infer the model parameters.
      """
  
      expected_output_files = ["inferred.pkl"]
      if args.plotting:
          expected_output_files.extend([each.format(args.plot_format) \
              for each in "chain.{}", "corner.{}", "acceptance-fractions.{}",
              "autocorrelation.{}"])
  
      # Optimise them first.
      model, data, metadata, optimised_theta = optimise(args,
          expected_output_files=expected_output_files, __return_result=True)
  
      # Get the inference parameters from the model configuration.
      kwargs = model._configuration.get("infer", {})
      [kwargs.pop(k, None) \
          for k in ("debug", "full_output", "initial_proposal", "data")]
  
      try:
          theta, chains, lnprobability, acceptance_fractions, sampler, info_dict \
              = model.infer(data, initial_proposal=optimised_theta, 
                  full_output=True, debug=args.debug, 
                  __keep_convolution_functions=True,
                  __show_progress_bar=True, **kwargs)
  
      except:
          logger.exception("Failed to infer model parameters")
          raise
  
      metadata["inferred"] = {
          "theta": theta,
          "chi_sq": info_dict["chi_sq"],
          "dof": info_dict["dof"],
          "r_chi_sq": info_dict["chi_sq"]/info_dict["dof"]
      }
  
      logger.info("Inferred parameters are:")
      _announce_theta(theta)
      
      # Write the results to file.
      _write_output(_prefix(args, "inferred.pkl"), metadata)
  
      # Write the chains, etc to disk.
      if args.save_chain_files:
          filename = _prefix(args, "chains.pkl")
          with open(filename, "wb") as f:
              pickle.dump(
                  (chains, lnprobability, acceptance_fractions, info_dict), f, -1)
          logger.info("Saved chains to {}".format(filename))
  
      # Make plots.
      if args.plotting:
          burn = info_dict["burn"]
  
          # Any truth values to plot?
          truths = model._configuration.get("truths", None)
          if truths:
              truths = [truths.get(p, np.nan) for p in model.parameters]
  
          # Labels?
          labels = model._configuration.get("labels", {})
          labels = [labels.get(p, p) for p in info_dict["parameters"]]
          
          # Acceptance fractions.
          fig = sick.plot.acceptance_fractions(acceptance_fractions,
              burn=burn)
          _ = _prefix(args, "acceptance-fractions.{}".format(args.plot_format))
          fig.savefig(_)
          logger.info("Saved acceptance fractions figure to {}".format(_))
  
          # Autocorrelation.
          fig = sick.plot.normalised_autocorrelation_function(chains, burn=burn)
          _ = _prefix(args, "auto-correlation.{}".format(args.plot_format))
          fig.savefig(_)
          logger.info("Saved auto-correlation figure to {}".format(_))
  
          # Chains.
          fig = sick.plot.chains(chains, labels=labels, burn=burn,
              truths=truths)
          _ = _prefix(args, "chains.{}".format(args.plot_format))
          fig.savefig(_)
          logger.info("Saved chains figure to {}".format(_))
  
          # Corner plots (astrophysical + all).
          N = len(model.grid_points.dtype.names)
          fig = sick.plot.corner(chains[:, burn:, :N].reshape(-1, N),
              labels=labels, truths=truths[:N] if truths else None)
          _ = _prefix(args, "corner.{}".format(args.plot_format))
          fig.savefig(_)
          logger.info("Saved corner plot (astrophysical parameters) to {}"\
              .format(_))
  
          if len(model.parameters) > N:
              fig = sick.plot.corner(chains[:, burn:, :].reshape(-1, len(theta)),
                  labels=labels, truths=truths)
              _ = _prefix(args, "corner-all.{}".format(args.plot_format))
              fig.savefig(_)
              logger.info("Saved corner plot (all parameters) to {}".format(_))
  
          # Projections.
          # Note here we need to scale the chains back to redshift so the data
          # are generated properly.
          fig = sick.plot.projection(data, model, 
              chains=chains[:, burn:, :]/info_dict["scales"],
              parameters=theta.keys())
          _ = _prefix(args, "projection.{}".format(args.plot_format))
          fig.savefig(_)
          logger.info("Saved projection plot to {}".format(_))
  
      model._destroy_convolution_functions()
  
      return None