def Func(arg_0='top/protein.pdb', arg_1='top/system.top',
            arg_2=0.9, arg_3='dodecahedron',
            arg_4=0, arg_5='NA', arg_6='CL',
            arg_7='tip4p', arg_8='SOL', arg_9=False,
            arg_10 = 'main.ndx', arg_11 = '"Protein"',
            arg_12='Func',
            **arg_13):
    """Put protein into box, add water, add counter-ions.

    Currently this really only supports solutes in water. If you need
    to embedd a protein in a membrane then you will require more
    sophisticated approaches.

    However, you *can* supply a protein already inserted in a
    bilayer. In this case you will probably want to set *distance* =
    ``None`` and also enable *with_membrane* = ``True`` (using extra
    big vdw radii for typical lipids).

    .. Note:: The defaults are suitable for solvating a globular
       protein in a fairly tight (increase *distance*!) dodecahedral
       box.

    :Arguments:
      *struct* : filename
          pdb or gro input structure
      *top* : filename
          Gromacs topology
      *distance* : float
          When solvating with water, make the box big enough so that
          at least *distance* nm water are between the solute *struct*
          and the box boundary.
          Set *boxtype*  to ``None`` in order to use a box size in the input
          file (gro or pdb).
      *boxtype* or *bt*: string
          Any of the box types supported by :class:`~gromacs.tools.Editconf`
          (triclinic, cubic, dodecahedron, octahedron). Set the box dimensions
          either with *distance* or the *box* and *angle* keywords.

          If set to ``None`` it will ignore *distance* and use the box
          inside the *struct* file.

          *bt* overrides the value of *boxtype*.
      *box*
          List of three box lengths [A,B,C] that are used by :class:`~gromacs.tools.Editconf`
          in combination with *boxtype* (``bt`` in :program:`editconf`) and *angles*.
          Setting *box* overrides *distance*.
      *angles*
          List of three angles (only necessary for triclinic boxes).
      *concentration* : float
          Concentration of the free ions in mol/l. Note that counter
          ions are added in excess of this concentration.
      *cation* and *anion* : string
          Molecule names of the ions. This depends on the chosen force field.
      *water* : string
          Name of the water model; one of "spc", "spce", "tip3p",
          "tip4p". This should be appropriate for the chosen force
          field. If an alternative solvent is required, simply supply the path to a box
          with solvent molecules (used by :func:`~gromacs.genbox`'s  *cs* argument)
          and also supply the molecule name via *solvent_name*.
      *solvent_name*
          Name of the molecules that make up the solvent (as set in the itp/top).
          Typically needs to be changed when using non-standard/non-water solvents.
          ["SOL"]
      *with_membrane* : bool
           ``True``: use special ``vdwradii.dat`` with 0.1 nm-increased radii on
           lipids. Default is ``False``.
      *ndx* : filename
          How to name the index file that is produced by this function.
      *mainselection* : string
          A string that is fed to :class:`~gromacs.tools.Make_ndx` and
          which should select the solute.
      *dirname* : directory name
          Name of the directory in which all files for the solvation stage are stored.
      *includes*
          List of additional directories to add to the mdp include path
      *kwargs*
          Additional arguments are passed on to
          :class:`~gromacs.tools.Editconf` or are interpreted as parameters to be
          changed in the mdp file.

    """
    arg_14 = Func_sol(arg_0=arg_0, arg_1=arg_1,
                      arg_2=arg_2, arg_3=arg_3,
                      arg_7=arg_7, arg_8=arg_8,
                      arg_9=arg_9,
                      arg_12=arg_12, **arg_13)

    arg_15 = Func_ion(arg_0=arg_14['struct'], arg_1=arg_1,
                      arg_4=arg_4, arg_5=arg_5, arg_6=arg_6,
                      arg_8=arg_8, arg_10=arg_10,
                      arg_11=arg_11, arg_12=arg_12,
                      **arg_13)
    return arg_15


def Func(**arg_0):
    """Run multiple energy minimizations one after each other.

    :Keywords:
      *integrators*
           list of integrators (from 'l-bfgs', 'cg', 'steep')
           [['bfgs', 'steep']]
      *nsteps*
           list of maximum number of steps; one for each integrator in
           in the *integrators* list [[100,1000]]
      *kwargs*
           mostly passed to :func:`gromacs.setup.energy_minimize`

    :Returns: dictionary with paths to final structure ('struct') and
              other files

    :Example:
       Conduct three minimizations:
         1. low memory Broyden-Goldfarb-Fletcher-Shannon (BFGS) for 30 steps
         2. steepest descent for 200 steps
         3. finish with BFGS for another 30 steps
       We also do a multi-processor minimization when possible (i.e. for steep
       (and conjugate gradient) by using a :class:`gromacs.run.MDrunner` class
       for a :program:`mdrun` executable compiled for OpenMP in 64 bit (see
       :mod:`gromacs.run` for details)::

          import gromacs.run
          gromacs.setup.Func(struct='solvate/ionized.gro',
                    mdrunner=gromacs.run.MDrunnerOpenMP64,
                    integrators=['l-bfgs', 'steep', 'l-bfgs'],
                    nsteps=[50,200, 50])

    .. Note:: You might have to prepare the mdp file carefully because at the
              moment one can only modify the *nsteps* parameter on a
              per-minimizer basis.
    """

    arg_1 = arg_0.pop('mdrunner', None)
    arg_2 = arg_0.pop('integrators', ['l-bfgs', 'steep'])
    arg_0.pop('integrator', None)  # clean input; we set intgerator from integrators
    arg_3 = arg_0.pop('nsteps', [100, 1000])

    arg_4 = ['em{0:03d}_{1!s}.pdb'.format(arg_6, arg_7) for arg_6,arg_7 in enumerate(arg_2)]
    arg_4[-1] = arg_0.pop('output', 'em.pdb')

    arg_5 = {'struct': arg_0.pop('struct', None)}  # fake output from energy_minimize()

    for arg_6, arg_7 in enumerate(arg_2):
        arg_8 = arg_5['struct']
        logger.info("[em %d] energy minimize with %s for maximum %d steps", arg_6, arg_7, arg_3[arg_6])
        arg_0.update({'struct':arg_8, 'output':arg_4[arg_6],
                       'integrator':arg_7, 'nsteps': arg_3[arg_6]})
        if not arg_7 == 'l-bfgs':
            arg_0['mdrunner'] = arg_1
        else:
            arg_0['mdrunner'] = None
            logger.warning("[em %d]  Not using mdrunner for L-BFGS because it cannot "
                           "do parallel runs.", arg_6)

        arg_5 = energy_minimize(**arg_0)

    return arg_5


def Func(arg_0='MD_POSRES', **arg_1):
    """Set up MD with position restraints.

    Additional itp files should be in the same directory as the top file.

    Many of the keyword arguments below already have sensible values. Note that
    setting *mainselection* = ``None`` will disable many of the automated
    choices and is often recommended when using your own mdp file.

    :Keywords:
       *dirname*
          set up under directory dirname [MD_POSRES]
       *struct*
          input structure (gro, pdb, ...) [em/em.pdb]
       *top*
          topology file [top/system.top]
       *mdp*
          mdp file (or use the template) [templates/md.mdp]
       *ndx*
          index file (supply when using a custom mdp)
       *includes*
          additional directories to search for itp files
       *mainselection*
          :program:`make_ndx` selection to select main group ["Protein"]
          (If ``None`` then no canonical index file is generated and
          it is the user's responsibility to set *tc_grps*,
          *tau_t*, and *ref_t* as keyword arguments, or provide the mdp template
          with all parameter pre-set in *mdp* and probably also your own *ndx*
          index file.)
       *deffnm*
          default filename for Gromacs run [md]
       *runtime*
          total length of the simulation in ps [1000]
       *dt*
          integration time step in ps [0.002]
       *qscript*
          script to submit to the queuing system; by default
          uses the template :data:`gromacs.config.qscript_template`, which can
          be manually set to another template from :data:`gromacs.config.templates`;
          can also be a list of template names.
       *qname*
          name to be used for the job in the queuing system [PR_GMX]
       *mdrun_opts*
          option flags for the :program:`mdrun` command in the queuing system
          scripts such as "-stepout 100". [""]
       *kwargs*
          remaining key/value pairs that should be changed in the template mdp
          file, eg ``nstxtcout=250, nstfout=250`` or command line options for
          ``grompp` such as ``maxwarn=1``.

          In particular one can also set **define** and activate
          whichever position restraints have been coded into the itp
          and top file. For instance one could have

             *define* = "-DPOSRES_MainChain -DPOSRES_LIGAND"

          if these preprocessor constructs exist. Note that there
          **must not be any space between "-D" and the value.**

          By default *define* is set to "-DPOSRES".

    :Returns: a dict that can be fed into :func:`gromacs.setup.MD`
              (but check, just in case, especially if you want to
              change the ``define`` parameter in the mdp file)

    .. Note:: The output frequency is drastically reduced for position
              restraint runs by default. Set the corresponding ``nst*``
              variables if you require more output. The `pressure coupling`_
              option *refcoord_scaling* is set to "com" by default (but can
              be changed via *kwargs*) and the pressure coupling
              algorithm itself is set to *Pcoupl* = "Berendsen" to
              run a stable simulation.

    .. _`pressure coupling`: http://manual.gromacs.org/online/mdp_opt.html#pc
    """

    logger.info("[{dirname!s}] Setting up MD with position restraints...".format(**vars()))
    arg_1.setdefault('struct', 'em/em.pdb')
    arg_1.setdefault('qname', 'PR_GMX')
    arg_1.setdefault('define', '-DPOSRES')
    # reduce size of output files
    arg_1.setdefault('nstxout', '50000')   # trr pos
    arg_1.setdefault('nstvout', '50000')   # trr veloc
    arg_1.setdefault('nstfout', '0')       # trr forces
    arg_1.setdefault('nstlog', '500')      # log file
    arg_1.setdefault('nstenergy', '2500')  # edr energy
    arg_1.setdefault('nstxtcout', '5000')  # xtc pos
    # try to get good pressure equilibration
    arg_1.setdefault('refcoord_scaling', 'com')
    arg_1.setdefault('Pcoupl', "Berendsen")

    arg_2 =  _setup_MD(arg_0, **arg_1)

    # clean up output kwargs
    arg_2.pop('define', None)          # but make sure that -DPOSRES does not stay...
    arg_2.pop('refcoord_scaling', None)
    arg_2.pop('Pcoupl', None)
    return arg_2


def Func(arg_0='Func', **arg_1):
    """Set up equilibrium Func.

    Additional itp files should be in the same directory as the top file.

    Many of the keyword arguments below already have sensible values. Note that
    setting *mainselection* = ``None`` will disable many of the automated
    choices and is often recommended when using your own mdp file.

    :Keywords:
       *dirname*
          set up under directory dirname [Func]
       *struct*
          input structure (gro, pdb, ...) [Func_POSRES/md_posres.pdb]
       *top*
          topology file [top/system.top]
       *mdp*
          mdp file (or use the template) [templates/md.mdp]
       *ndx*
          index file (supply when using a custom mdp)
       *includes*
          additional directories to search for itp files
       *mainselection*
          ``make_ndx`` selection to select main group ["Protein"]
          (If ``None`` then no canonical index file is generated and
          it is the user's responsibility to set *tc_grps*,
          *tau_t*, and *ref_t* as keyword arguments, or provide the mdp template
          with all parameter pre-set in *mdp* and probably also your own *ndx*
          index file.)
       *deffnm*
          default filename for Gromacs run [md]
       *runtime*
          total length of the simulation in ps [1000]
       *dt*
          integration time step in ps [0.002]
       *qscript*
          script to submit to the queuing system; by default
          uses the template :data:`gromacs.config.qscript_template`, which can
          be manually set to another template from :data:`gromacs.config.templates`;
          can also be a list of template names.
       *qname*
          name to be used for the job in the queuing system [Func_GMX]
       *mdrun_opts*
          option flags for the :program:`mdrun` command in the queuing system
          scripts such as "-stepout 100 -dgdl". [""]
       *kwargs*
          remaining key/value pairs that should be changed in the template mdp
          file, e.g. ``nstxtcout=250, nstfout=250`` or command line options for
          :program`grompp` such as ``maxwarn=1``.

    :Returns: a dict that can be fed into :func:`gromacs.setup.Func`
              (but check, just in case, especially if you want to
              change the *define* parameter in the mdp file)
    """

    logger.info("[{dirname!s}] Setting up Func...".format(**vars()))
    arg_1.setdefault('struct', 'Func_POSRES/md.gro')
    arg_1.setdefault('qname', 'Func_GMX')
    return _setup_Func(arg_0, **arg_1)


def Func(arg_0, arg_1=None, arg_2='md', arg_3='MD', arg_4=None,
                            arg_5=None, arg_6=1.0, arg_7=None, arg_8=None,
                            arg_9=None, **arg_10):
    """Write scripts for queuing systems.

    This sets up queuing system run scripts with a simple search and replace in
    templates. See :func:`gromacs.cbook.edit_txt` for details. Shell scripts
    are made executable.

    :Arguments:
      *templates*
          Template file or list of template files. The "files" can also be names
          or symbolic names for templates in the templates directory. See
          :mod:`gromacs.config` for details and rules for writing templates.
      *prefix*
          Prefix for the final run script filename; by default the filename will be
          the same as the template. [None]
      *dirname*
          Directory in which to place the submit scripts. [.]
      *deffnm*
          Default filename prefix for :program:`mdrun` ``-deffnm`` [md]
      *jobname*
          Name of the job in the queuing system. [MD]
      *budget*
          Which budget to book the runtime on [None]
      *startdir*
          Explicit path on the remote system (for run scripts that need to `cd`
          into this directory at the beginning of execution) [None]
      *mdrun_opts*
          String of additional options for :program:`mdrun`.
      *walltime*
          Maximum runtime of the job in hours. [1]
      *npme*
          number of PME nodes
      *jobarray_string*
          Multi-line string that is spliced in for job array functionality
          (see :func:`gromacs.qsub.generate_submit_array`; do not use manually)
      *kwargs*
          all other kwargs are ignored

    :Returns: list of generated run scripts
    """
    if not arg_3[0].isalpha():
        arg_3 = 'MD_'+arg_3
        arg_11 = "To make the jobname legal it must start with a letter: changed to {0!r}".format(arg_3)
        logger.warn(arg_11)
        warnings.warn(arg_11, category=AutoCorrectionWarning)
    if arg_1 is None:
        arg_1 = ""
    if arg_5 is not None:
        arg_5 = '"'+str(arg_5)+'"'  # TODO: could test if quotes already present

    arg_12 = arg_10.pop('dirname', os.path.curdir)

    arg_13 = Timedelta(hours=arg_6)
    arg_6 = arg_13.strftime("%h:%M:%S")
    arg_14 = arg_13.ashours

    def write_script(arg_15):
        arg_16 = os.path.join(arg_12, arg_1 + os.path.basename(arg_15))
        logger.info("Setting up queuing system script {submitscript!r}...".format(**vars()))
        # These substitution rules are documented for the user in the module doc string
        arg_17 = detect_queuing_system(arg_15)
        if arg_17 is not None and (arg_17.name == 'Slurm'):
            cbook.edit_txt(arg_15,
                           [('^ *DEFFNM=','(?<==)(.*)', arg_2),
                            ('^#.*(-J)', '((?<=-J\s))\s*\w+', arg_3),
                            ('^#.*(-A|account_no)', '((?<=-A\s)|(?<=account_no\s))\s*\w+', arg_4),
                            ('^#.*(-t)', '(?<=-t\s)(\d+:\d+:\d+)', arg_6),
                            ('^ *WALL_HOURS=', '(?<==)(.*)', arg_14),
                            ('^ *STARTDIR=', '(?<==)(.*)', arg_8),
                            ('^ *NPME=', '(?<==)(.*)', arg_9),
                            ('^ *MDRUN_OPTS=', '(?<==)("")', arg_5),  # only replace literal ""
                            ('^# JOB_ARRAY_PLACEHOLDER', '^.*$', arg_7),
                            ],
                           newname=arg_16)
            arg_18 = os.path.splitext(arg_16)[1]
        else:
            cbook.edit_txt(arg_15,
                           [('^ *DEFFNM=','(?<==)(.*)', arg_2),
                            ('^#.*(-N|job_name)', '((?<=-N\s)|(?<=job_name\s))\s*\w+', arg_3),
                            ('^#.*(-A|account_no)', '((?<=-A\s)|(?<=account_no\s))\s*\w+', arg_4),
                            ('^#.*(-l walltime|wall_clock_limit)', '(?<==)(\d+:\d+:\d+)', arg_6),
                            ('^ *WALL_HOURS=', '(?<==)(.*)', arg_14),
                            ('^ *STARTDIR=', '(?<==)(.*)', arg_8),
                            ('^ *NPME=', '(?<==)(.*)', arg_9),
                            ('^ *MDRUN_OPTS=', '(?<==)("")', arg_5),  # only replace literal ""
                            ('^# JOB_ARRAY_PLACEHOLDER', '^.*$', arg_7),
                           ],
                           newname=arg_16)
            arg_18 = os.path.splitext(arg_16)[1]
        if arg_18 in ('.sh', '.csh', '.bash'):
            os.chmod(arg_16, 0o755)
        return arg_16

    return [write_script(arg_15) for arg_15 in config.get_templates(arg_0)]


def Func(arg_0, arg_1):
        """Primitive queuing system detection; only looks at suffix at the moment."""
        arg_2 = os.path.splitext(arg_1)[1].lower()
        if arg_2.startswith('.'):
            arg_2 = arg_2[1:]
        return arg_0.suffix == arg_2


def Func(arg_0, arg_1):
    """Returns all dates from first to last included."""
    return [arg_0 + timedelta(days=arg_2)
            for arg_2 in range(1 + (arg_1 - arg_0).days)]


def Func(arg_0, arg_1):
        """Fill missing rates of a currency.

        This is done by linear interpolation of the two closest available rates.

        :param str currency: The currency to fill missing rates for.
        """
        arg_2 = arg_0._rates[arg_1]

        # tmp will store the closest rates forward and backward
        arg_3 = defaultdict(lambda: [None, None])

        for arg_4 in sorted(arg_2):
            arg_5 = arg_2[arg_4]
            if arg_5 is not None:
                arg_6 = arg_5
                arg_7 = 0
            else:
                arg_7 += 1
                arg_3[arg_4][0] = arg_6, arg_7

        for arg_4 in sorted(arg_2, reverse=True):
            arg_5 = arg_2[arg_4]
            if arg_5 is not None:
                arg_6 = arg_5
                arg_7 = 0
            else:
                arg_7 += 1
                arg_3[arg_4][1] = arg_6, arg_7

        for arg_4 in sorted(arg_3):
            (arg_8, arg_9), (arg_10, arg_11) = arg_3[arg_4]
            arg_2[arg_4] = (arg_8 * arg_11 + arg_10 * arg_9) / (arg_9 + arg_11)
            if arg_0.verbose:
                print(('{0}: filling {1} missing rate using {2} ({3}d old) and '
                       '{4} ({5}d later)').format(arg_1, arg_4, arg_8, arg_9, arg_10, arg_11))


def Func(arg_0, arg_1, arg_2, arg_3='EUR', arg_4=None):
        """Convert amount from a currency to another one.

        :param float amount: The amount of `currency` to Func.
        :param str currency: The currency to Func from.
        :param str new_currency: The currency to Func to.
        :param datetime.date date: Use the conversion rate of this date. If this
            is not given, the most recent rate is used.

        :return: The value of `amount` in `new_currency`.
        :rtype: float

        >>> from datetime import date
        >>> c = CurrencyConverter()
        >>> c.Func(100, 'EUR', 'USD', date=date(2014, 3, 28))
        137.5...
        >>> c.Func(100, 'USD', date=date(2014, 3, 28))
        72.67...
        >>> c.Func(100, 'BGN', date=date(2010, 11, 21))
        Traceback (most recent call last):
        RateNotFoundError: BGN has no rate for 2010-11-21
        """
        for arg_5 in arg_2, arg_3:
            if arg_5 not in arg_0.currencies:
                raise ValueError('{0} is not a supported currency'.format(arg_5))

        if arg_4 is None:
            arg_4 = arg_0.bounds[arg_2].last_date
        else:
            try:
                arg_4 = arg_4.date()  # fallback if input was a datetime object
            except AttributeError:
                pass

        arg_6 = arg_0._get_rate(arg_2, arg_4)
        arg_7 = arg_0._get_rate(arg_3, arg_4)

        return float(arg_1) / arg_6 * arg_7


def Func(arg_0, arg_1, arg_2, arg_3=2):
    """Animate given frame for set number of iterations.

    Parameters
    ----------
    frames : list
        Frames for animating
    interval : float
        Interval between two frames
    name : str
        Name of animation
    iterations : int, optional
        Number of loops for animations
    """
    for arg_4 in range(arg_3):
        for arg_5 in arg_0:
            arg_5 = get_coded_text(arg_5)
            arg_6 = "\r{0} {1}".format(arg_5, arg_2)
            sys.stdout.write(arg_6)
            sys.stdout.write(CLEAR_LINE)
            sys.stdout.flush()
            time.sleep(0.001 * arg_1)


def Func(arg_0):
    """Compute the total number of unmasked regular pixels in a masks."""

    arg_1 = 0

    for arg_2 in range(arg_0.shape[0]):
        for arg_3 in range(arg_0.shape[1]):
            if not arg_0[arg_2, arg_3]:
                arg_1 += 1

    return arg_1


def Func(arg_0, arg_1, arg_2, arg_3,
                                                           arg_4=(0.0, 0.0)):
    """Compute an annular masks from an input inner and outer masks radius and regular shape."""

    arg_5 = np.full(arg_0, True)

    arg_6 = mask_centres_from_shape_pixel_scale_and_centre(arg_0=arg_5.shape, arg_1=arg_1, arg_4=arg_4)

    for arg_7 in range(arg_5.shape[0]):
        for arg_8 in range(arg_5.shape[1]):

            arg_9 = (arg_7 - arg_6[0]) * arg_1
            arg_10 = (arg_8 - arg_6[1]) * arg_1

            arg_11 = np.sqrt(arg_10 ** 2 + arg_9 ** 2)

            if arg_3 >= arg_11 >= arg_2:
                arg_5[arg_7, arg_8] = False

    return arg_5


def Func(arg_0, arg_1):
    """Compute a blurring masks from an input masks and psf shape.

    The blurring masks corresponds to all pixels which are outside of the masks but will have a fraction of their \
    light blur into the masked region due to PSF convolution."""

    arg_2 = np.full(arg_0.shape, True)

    for arg_3 in range(arg_0.shape[0]):
        for arg_4 in range(arg_0.shape[1]):
            if not arg_0[arg_3, arg_4]:
                for arg_5 in range((-arg_1[0] + 1) // 2, (arg_1[0] + 1) // 2):
                    for arg_6 in range((-arg_1[1] + 1) // 2, (arg_1[1] + 1) // 2):
                        if 0 <= arg_4 + arg_6 <= arg_0.shape[1] - 1 and 0 <= arg_3 + arg_5 <= arg_0.shape[0] - 1:
                            if arg_0[arg_3 + arg_5, arg_4 + arg_6]:
                                arg_2[arg_3 + arg_5, arg_4 + arg_6] = False
                        else:
                            raise exc.MaskException(
                                "setup_blurring_mask extends beyond the sub_grid_size of the masks - pad the "
                                "datas array before masking")

    return arg_2


def Func(arg_0):
    """Compute a 1D array listing all edge pixel indexes in the masks. An edge pixel is a pixel which is not fully \
    surrounding by False masks values i.e. it is on an edge."""

    arg_1 = total_Func(arg_0)

    arg_2 = np.zeros(arg_1)
    arg_3 = 0
    arg_4 = 0

    for arg_5 in range(arg_0.shape[0]):
        for arg_6 in range(arg_0.shape[1]):
            if not arg_0[arg_5, arg_6]:
                if arg_0[arg_5 + 1, arg_6] or arg_0[arg_5 - 1, arg_6] or arg_0[arg_5, arg_6 + 1] or arg_0[arg_5, arg_6 - 1] or \
                        arg_0[arg_5 + 1, arg_6 + 1] or arg_0[arg_5 + 1, arg_6 - 1] or arg_0[arg_5 - 1, arg_6 + 1] or arg_0[arg_5 - 1, arg_6 - 1]:
                    arg_2[arg_3] = arg_4
                    arg_3 += 1

                arg_4 += 1

    return arg_2


def Func(arg_0, arg_1, arg_2, arg_3, arg_4):
    """Output the figure, either as an image on the screen or to the hard-disk as a .png or .fits file.

    Parameters
    -----------
    array : ndarray
        The 2D array of image to be output, required for outputting the image as a fits file.
    as_subplot : bool
        Whether the figure is part of subplot, in which case the figure is not output so that the entire subplot can \
        be output instead using the *output_subplot_array* function.
    output_path : str
        The path on the hard-disk where the figure is output.
    output_filename : str
        The filename of the figure that is output.
    output_format : str
        The format the figue is output:
        'show' - display on computer screen.
        'png' - output to hard-disk as a png.
        'fits' - output to hard-disk as a fits file.'
    """
    if not arg_1:

        if arg_4 is 'show':
            plt.show()
        elif arg_4 is 'png':
            plt.savefig(arg_2 + arg_3 + '.png', bbox_inches='tight')
        elif arg_4 is 'fits':
            array_util.numpy_array_2d_to_fits(array_2d=arg_0, file_path=arg_2 + arg_3 + '.fits',
                                              overwrite=True)


def Func(arg_0, arg_1, arg_2):
    """Output a figure which consists of a set of subplot,, either as an image on the screen or to the hard-disk as a \
    .png file.

    Parameters
    -----------
    output_path : str
        The path on the hard-disk where the figure is output.
    output_filename : str
        The filename of the figure that is output.
    output_format : str
        The format the figue is output:
        'show' - display on computer screen.
        'png' - output to hard-disk as a png.
    """
    if arg_2 is 'show':
        plt.show()
    elif arg_2 is 'png':
        plt.savefig(arg_0 + arg_1 + '.png', bbox_inches='tight')
    elif arg_2 is 'fits':
        raise exc.PlottingException('You cannot output a subplots with format .fits')


def Func(arg_0):
    """Generate an image psf shape tag, to customize phase names based on size of the image PSF that the original PSF \
    is trimmed to for faster run times.

    This changes the phase name 'phase_name' as follows:

    image_psf_shape = 1 -> phase_name
    image_psf_shape = 2 -> phase_name_image_psf_shape_2
    image_psf_shape = 2 -> phase_name_image_psf_shape_2
    """
    if arg_0 is None:
        return ''
    else:
        arg_1 = str(arg_0[0])
        arg_2 = str(arg_0[1])
        return ('_image_psf_' + arg_1 + 'x' + arg_2)


def Func(arg_0):
    """Generate an inversion psf shape tag, to customize phase names based on size of the inversion PSF that the \
    original PSF is trimmed to for faster run times.

    This changes the phase name 'phase_name' as follows:

    inversion_psf_shape = 1 -> phase_name
    inversion_psf_shape = 2 -> phase_name_inversion_psf_shape_2
    inversion_psf_shape = 2 -> phase_name_inversion_psf_shape_2
    """
    if arg_0 is None:
        return ''
    else:
        arg_1 = str(arg_0[0])
        arg_2 = str(arg_0[1])
        return ('_inv_psf_' + arg_1 + 'x' + arg_2)


def Func(arg_0, arg_1):
    """This function determines whether the tracer should compute the deflections at the next plane.

    This is True if there is another plane after this plane, else it is False..

    Parameters
    -----------
    plane_index : int
        The index of the plane we are deciding if we should compute its deflections.
    total_planes : int
        The total number of planes."""

    if arg_0 < arg_1 - 1:
        return True
    elif arg_0 == arg_1 - 1:
        return False
    else:
        raise exc.RayTracingException('A galaxy was not correctly allocated its previous / next redshifts')


def Func(arg_0, arg_1):
    """Given a plane and scaling factor, compute a set of scaled deflections.

    Parameters
    -----------
    plane : plane.Plane
        The plane whose deflection stack is scaled.
    scaling_factor : float
        The factor the deflection angles are scaled by, which is typically the scaling factor between redshifts for \
        multi-plane lensing.
    """

    def scale(arg_2):
        return np.multiply(arg_1, arg_2)

    if arg_0.deflection_stack is not None:
        return arg_0.deflection_stack.apply_function(scale)
    else:
        return None


def Func(arg_0, arg_1, arg_2):
    """From the pixel-neighbors, setup the regularization matrix using the constant regularization scheme.

    Parameters
    ----------
    coefficients : tuple
        The regularization coefficients which controls the degree of smoothing of the inversion reconstruction.
    pixel_neighbors : ndarray
        An array of length (total_pixels) which provides the index of all neighbors of every pixel in \
        the Voronoi grid (entries of -1 correspond to no neighbor).
    pixel_neighbors_size : ndarrayy
        An array of length (total_pixels) which gives the number of neighbors of every pixel in the \
        Voronoi grid.
    """

    arg_3 = len(arg_1)

    arg_4 = np.zeros(shape=(arg_3, arg_3))

    arg_5 = arg_0[0] ** 2.0

    for arg_6 in range(arg_3):
        arg_4[arg_6, arg_6] += 1e-8
        for arg_7 in range(arg_2[arg_6]):
            arg_8 = arg_1[arg_6, arg_7]
            arg_4[arg_6, arg_6] += arg_5
            arg_4[arg_6, arg_8] -= arg_5

    return arg_4


def Func(arg_0, arg_1, arg_2, arg_3, arg_4):
    """Setup the colorbar of the figure, specifically its ticksize and the size is appears relative to the figure.

    Parameters
    -----------
    cb_ticksize : int
        The size of the tick labels on the colorbar.
    cb_fraction : float
        The fraction of the figure that the colorbar takes up, which resizes the colorbar relative to the figure.
    cb_pad : float
        Pads the color bar in the figure, which resizes the colorbar relative to the figure.
    cb_tick_values : [float]
        Manually specified values of where the colorbar tick labels appear on the colorbar.
    cb_tick_labels : [float]
        Manually specified labels of the color bar tick labels, which appear where specified by cb_tick_values.
    """

    if arg_3 is None and arg_4 is None:
        arg_5 = plt.colorbar(fraction=arg_1, pad=arg_2)
    elif arg_3 is not None and arg_4 is not None:
        arg_5 = plt.colorbar(fraction=arg_1, pad=arg_2, ticks=arg_3)
        arg_5.ax.set_yticklabels(arg_4)
    else:
        raise exc.PlottingException('Only 1 entry of cb_tick_values or cb_tick_labels was input. You must either supply'
                                    'both the values and labels, or neither.')

    arg_5.ax.tick_params(labelsize=arg_0)


def Func(arg_0, arg_1, arg_2, arg_3, arg_4):
    """Plot the mask of the array on the figure.

    Parameters
    -----------
    mask : ndarray of data.array.mask.Mask
        The mask applied to the array, the edge of which is plotted as a set of points over the plotted array.
    units : str
        The units of the y / x axis of the plots, in arc-seconds ('arcsec') or kiloparsecs ('kpc').
    kpc_per_arcsec : float or None
        The conversion factor between arc-seconds and kiloparsecs, required to plot the units in kpc.
    pointsize : int
        The size of the points plotted to show the mask.
    """

    if arg_0 is not None:

        plt.gca()
        arg_5 = arg_0.masked_grid_index_to_pixel[arg_0.edge_pixels] + 0.5
        if arg_4 is not None:
            arg_5 -= arg_4
        arg_6 = arg_0.grid_pixels_to_grid_arcsec(grid_pixels=arg_5)
        arg_7 = convert_grid_units(array=arg_0, grid_arcsec=arg_6, arg_1=arg_1,
                                          arg_2=arg_2)

        plt.scatter(y=arg_7[:,0], x=arg_7[:,1], s=arg_3, c='k')


def Func(arg_0, arg_1, arg_2, arg_3, arg_4, arg_5):
    """Plot the borders of the mask or the array on the figure.

    Parameters
    -----------t.
    mask : ndarray of data.array.mask.Mask
        The mask applied to the array, the edge of which is plotted as a set of points over the plotted array.
    should_Func : bool
        If a mask is supplied, its borders pixels (e.g. the exterior edge) is plotted if this is *True*.
    units : str
        The units of the y / x axis of the plots, in arc-seconds ('arcsec') or kiloparsecs ('kpc').
    kpc_per_arcsec : float or None
        The conversion factor between arc-seconds and kiloparsecs, required to plot the units in kpc.
    border_pointsize : int
        The size of the points plotted to show the borders.
    """
    if arg_1 and arg_0 is not None:

        plt.gca()
        arg_6 = arg_0.masked_grid_index_to_pixel[arg_0.border_pixels]

        if arg_5 is not None:
            arg_6 -= arg_5

        arg_7 = arg_0.grid_pixels_to_grid_arcsec(grid_pixels=arg_6)
        arg_8 = convert_grid_units(array=arg_0, grid_arcsec=arg_7, arg_2=arg_2,
                                          arg_3=arg_3)

        plt.scatter(y=arg_8[:,0], x=arg_8[:,1], s=arg_4, c='y')


def Func(arg_0, arg_1, arg_2, arg_3, arg_4, arg_5):
    """Plot a grid of points over the array of data on the figure.

     Parameters
     -----------.
     grid_arcsec : ndarray or data.array.grids.RegularGrid
         A grid of (y,x) coordinates in arc-seconds which may be plotted over the array.
     array : data.array.scaled_array.ScaledArray
        The 2D array of data which is plotted.
     units : str
         The units of the y / x axis of the plots, in arc-seconds ('arcsec') or kiloparsecs ('kpc').
     kpc_per_arcsec : float or None
         The conversion factor between arc-seconds and kiloparsecs, required to plot the units in kpc.
     grid_pointsize : int
         The size of the points plotted to show the grid.
     """
    if arg_0 is not None:

        if arg_5 is not None:
            arg_0 -= arg_5

        arg_6 = convert_grid_units(arg_0=arg_0, arg_1=arg_1, arg_2=arg_2,
                                        arg_3=arg_3)

        plt.scatter(y=np.asarray(arg_6[:, 0]), x=np.asarray(arg_6[:, 1]), s=arg_4, c='k')


def Func(arg_0):
        """The mapping matrix is a matrix representing the mapping between every unmasked pixel of a grid and \
        the pixels of a pixelization. Non-zero entries signify a mapping, whereas zeros signify no mapping.

        For example, if the regular grid has 5 pixels and the pixelization 3 pixels, with the following mappings:

        regular pixel 0 -> pixelization pixel 0
        regular pixel 1 -> pixelization pixel 0
        regular pixel 2 -> pixelization pixel 1
        regular pixel 3 -> pixelization pixel 1
        regular pixel 4 -> pixelization pixel 2

        The mapping matrix (which is of dimensions regular_pixels x pixelization_pixels) would appear as follows:

        [1, 0, 0] [0->0]
        [1, 0, 0] [1->0]
        [0, 1, 0] [2->1]
        [0, 1, 0] [3->1]
        [0, 0, 1] [4->2]

        The mapping matrix is in fact built using the sub-grid of the grid-stack, whereby each regular-pixel is \
        divided into a regular grid of sub-pixels which are all paired to pixels in the pixelization. The entires \
        in the mapping matrix now become fractional values dependent on the sub-grid size. For example, for a 2x2 \
        sub-grid in each pixel (which means the fraction value is 1.0/(2.0^2) = 0.25, if we have the following mappings:

        regular pixel 0 -> sub pixel 0 -> pixelization pixel 0
        regular pixel 0 -> sub pixel 1 -> pixelization pixel 1
        regular pixel 0 -> sub pixel 2 -> pixelization pixel 1
        regular pixel 0 -> sub pixel 3 -> pixelization pixel 1
        regular pixel 1 -> sub pixel 0 -> pixelization pixel 1
        regular pixel 1 -> sub pixel 1 -> pixelization pixel 1
        regular pixel 1 -> sub pixel 2 -> pixelization pixel 1
        regular pixel 1 -> sub pixel 3 -> pixelization pixel 1
        regular pixel 2 -> sub pixel 0 -> pixelization pixel 2
        regular pixel 2 -> sub pixel 1 -> pixelization pixel 2
        regular pixel 2 -> sub pixel 2 -> pixelization pixel 3
        regular pixel 2 -> sub pixel 3 -> pixelization pixel 3

        The mapping matrix (which is still of dimensions regular_pixels x source_pixels) would appear as follows:

        [0.25, 0.75, 0.0, 0.0] [1 sub-pixel maps to pixel 0, 3 map to pixel 1]
        [ 0.0,  1.0, 0.0, 0.0] [All sub-pixels map to pixel 1]
        [ 0.0,  0.0, 0.5, 0.5] [2 sub-pixels map to pixel 2, 2 map to pixel 3]
        """
        return mapper_util.Func_from_sub_to_pix(sub_to_pix=arg_0.sub_to_pix, pixels=arg_0.pixels,
                                                          regular_pixels=arg_0.grid_stack.regular.shape[0],
                                                          sub_to_regular=arg_0.grid_stack.sub.sub_to_regular,
                                                          sub_grid_fraction=arg_0.grid_stack.sub.sub_grid_fraction)


def Func(arg_0):
        """Compute the mappings between a pixelization's pixels and the unmasked regular-grid pixels. These mappings \
        are determined after the regular-grid is used to determine the pixelization.

        The pixelization's pixels map to different number of regular-grid pixels, thus a list of lists is used to \
        represent these mappings"""
        Func = [[] for _ in range(arg_0.pixels)]

        for arg_2, arg_3 in enumerate(arg_0.regular_to_pix):

            Func[arg_3].append(arg_2)

        return Func


def Func(arg_0):
        """The 1D index mappings between the regular pixels and Voronoi pixelization pixels."""
        return mapper_util.voronoi_Func_from_grids_and_geometry(regular_grid=arg_0.grid_stack.regular,
               regular_to_nearest_pix=arg_0.grid_stack.pix.regular_to_nearest_pix,
               pixel_centres=arg_0.geometry.pixel_centres, pixel_neighbors=arg_0.geometry.pixel_neighbors,
               pixel_neighbors_size=arg_0.geometry.pixel_neighbors_size).astype('int')


def Func(arg_0):
        """  The 1D index mappings between the sub pixels and Voronoi pixelization pixels. """
        return mapper_util.voronoi_Func_from_grids_and_geometry(sub_grid=arg_0.grid_stack.sub,
               regular_to_nearest_pix=arg_0.grid_stack.pix.regular_to_nearest_pix,
               sub_to_regular=arg_0.grid_stack.sub.sub_to_regular, pixel_centres=arg_0.geometry.pixel_centres,
               pixel_neighbors=arg_0.geometry.pixel_neighbors,
               pixel_neighbors_size=arg_0.geometry.pixel_neighbors_size).astype('int')


def Func(arg_0, arg_1, arg_2=-1):
    """
    Generate a two-dimensional poisson noise_maps-mappers from an image.

    Values are computed from a Poisson distribution using the image's input values in units of counts.

    Parameters
    ----------
    image : ndarray
        The 2D image, whose values in counts are used to draw Poisson noise_maps values.
    exposure_time_map : Union(ndarray, int)
        2D array of the exposure time in each pixel used to convert to / from counts and electrons per second.
    seed : int
        The seed of the random number generator, used for the random noise_maps maps.

    Returns
    -------
    poisson_noise_map: ndarray
        An array describing simulated poisson noise_maps
    """
    setup_random_seed(arg_2)
    arg_3 = np.multiply(arg_0, arg_1)
    return arg_0 - np.divide(np.random.poisson(arg_3, arg_0.shape), arg_1)


def Func(arg_0, arg_1, arg_2,
                              arg_3,
                              arg_4):
    """Factory for loading the background noise-map from a .fits file.

    This factory also includes a number of routines for converting the background noise-map from from other units (e.g. \
    a weight map).

    Parameters
    ----------
    background_noise_map_path : str
        The path to the background_noise_map .fits file containing the background noise-map \
        (e.g. '/path/to/background_noise_map.fits')
    background_noise_map_hdu : int
        The hdu the background_noise_map is contained in the .fits file specified by *background_noise_map_path*.
    pixel_scale : float
        The size of each pixel in arc seconds.
    convert_background_noise_map_from_weight_map : bool
        If True, the bacground noise-map loaded from the .fits file is converted from a weight-map to a noise-map (see \
        *NoiseMap.from_weight_map).
    convert_background_noise_map_from_inverse_noise_map : bool
        If True, the background noise-map loaded from the .fits file is converted from an inverse noise-map to a \
        noise-map (see *NoiseMap.from_inverse_noise_map).
    """
    arg_5 = sum([arg_3,
                                        arg_4])

    if arg_5 == 0 and arg_0 is not None:
        return NoiseMap.from_fits_with_pixel_scale(file_path=arg_0, hdu=arg_1,
                                                   arg_2=arg_2)
    elif arg_3 and arg_0 is not None:
        arg_6 = Array.from_fits(file_path=arg_0, hdu=arg_1)
        return NoiseMap.from_weight_map(arg_6=arg_6, arg_2=arg_2)
    elif arg_4 and arg_0 is not None:
        arg_7 = Array.from_fits(file_path=arg_0, hdu=arg_1)
        return NoiseMap.from_inverse_noise_map(arg_7=arg_7, arg_2=arg_2)
    else:
        return None


def Func(arg_0, arg_1, arg_2, arg_3=False):
    """Factory for loading the psf from a .fits file.

    Parameters
    ----------
    psf_path : str
        The path to the psf .fits file containing the psf (e.g. '/path/to/psf.fits')
    psf_hdu : int
        The hdu the psf is contained in the .fits file specified by *psf_path*.
    pixel_scale : float
        The size of each pixel in arc seconds.
    renormalize : bool
        If True, the PSF is renoralized such that all elements sum to 1.0.
    """
    if arg_3:
        return PSF.from_fits_renormalized(file_path=arg_0, hdu=arg_1, arg_2=arg_2)
    if not arg_3:
        return PSF.from_fits_with_scale(file_path=arg_0, hdu=arg_1, arg_2=arg_2)


def Func(arg_0, arg_1, arg_2, arg_3, arg_4,
                           arg_5, arg_6):
    """Factory for loading the exposure time map from a .fits file.

    This factory also includes a number of routines for computing the exposure-time map from other unblurred_image_1d \
    (e.g. the background noise-map).

    Parameters
    ----------
    exposure_time_map_path : str
        The path to the exposure_time_map .fits file containing the exposure time map \
        (e.g. '/path/to/exposure_time_map.fits')
    exposure_time_map_hdu : int
        The hdu the exposure_time_map is contained in the .fits file specified by *exposure_time_map_path*.
    pixel_scale : float
        The size of each pixel in arc seconds.
    shape : (int, int)
        The shape of the image, required if a single value is used to calculate the exposure time map.
    exposure_time : float
        The exposure-time used to compute the expsure-time map if only a single value is used.
    exposure_time_map_from_inverse_noise_map : bool
        If True, the exposure-time map is computed from the background noise_map map \
        (see *ExposureTimeMap.from_background_noise_map*)
    inverse_noise_map : ndarray
        The background noise-map, which the Poisson noise-map can be calculated using.
    """
    arg_7 = sum([arg_5])

    if arg_4 is not None and arg_0 is not None:
        raise exc.DataException(
            'You have supplied both a exposure_time_map_path to an exposure time map and an exposure time. Only'
            'one quantity should be supplied.')

    if arg_7 == 0:

        if arg_4 is not None and arg_0 is None:
            return ExposureTimeMap.single_value(value=arg_4, arg_2=arg_2, arg_3=arg_3)
        elif arg_4 is None and arg_0 is not None:
            return ExposureTimeMap.from_fits_with_pixel_scale(file_path=arg_0,
                                                              hdu=arg_1, arg_2=arg_2)

    else:

        if arg_5:
            return ExposureTimeMap.from_exposure_time_and_inverse_noise_map(arg_2=arg_2,
                                                                            arg_4=arg_4,
                                                                            arg_6=arg_6)


def Func(arg_0, arg_1, arg_2):
    """Factory for loading the background sky from a .fits file.

    Parameters
    ----------
    background_sky_map_path : str
        The path to the background_sky_map .fits file containing the background sky map \
        (e.g. '/path/to/background_sky_map.fits').
    background_sky_map_hdu : int
        The hdu the background_sky_map is contained in the .fits file specified by *background_sky_map_path*.
    pixel_scale : float
        The size of each pixel in arc seconds.
    """
    if arg_0 is not None:
        return ScaledSquarePixelArray.from_fits_with_pixel_scale(file_path=arg_0,
                                                                 hdu=arg_1, arg_2=arg_2)
    else:
        return None


def Func(arg_0):
        """The estimated absolute_signal-to-noise_maps mappers of the image."""
        return np.divide(np.abs(arg_0.image), arg_0.noise_map)


def Func(arg_0, arg_1, arg_2, arg_3, arg_4=(0.0, 0.0), arg_5=1.0, arg_6=0.0):
        """Simulate the PSF as an elliptical Gaussian profile."""
        from autolens.model.profiles.light_profiles import EllipticalGaussian
        arg_7 = EllipticalGaussian(arg_4=arg_4, arg_5=arg_5, arg_6=arg_6, intensity=1.0, arg_3=arg_3)
        arg_8 = grid_util.regular_grid_1d_masked_from_mask_pixel_scales_and_origin(mask=np.full(arg_1, False),
                                                                                pixel_scales=(
                                                                                arg_2, arg_2))
        arg_9 = arg_7.intensities_from_grid(grid=arg_8)
        arg_10 = mapping_util.map_unmasked_1d_array_to_2d_array_from_array_1d_and_shape(array_1d=arg_9,
                                                                                arg_1=arg_1)
        return PSF(array=arg_10, arg_2=arg_2, renormalize=True)


def Func(arg_0, arg_1, arg_2, arg_3):
        """Loads a PSF from fits and renormalizes it

        Parameters
        ----------
        pixel_scale
        file_path: String
            The path to the file containing the PSF
        hdu : int
            The HDU the PSF is stored in the .fits file.

        Returns
        -------
        psf: PSF
            A renormalized PSF instance
        """
        arg_4 = PSF.from_fits_with_scale(arg_1, arg_2, arg_3)
        arg_4[:, :] = np.divide(arg_4, np.sum(arg_4))
        return arg_4


def Func(arg_0, arg_1, arg_2, arg_3):
        """
        Loads the PSF from a .fits file.

        Parameters
        ----------
        pixel_scale
        file_path: String
            The path to the file containing the PSF
        hdu : int
            The HDU the PSF is stored in the .fits file.
        """
        return arg_0(array=array_util.numpy_array_2d_from_fits(arg_1, arg_2), arg_3=arg_3)


def Func(arg_0):
        """Renormalize the PSF such that its data_vector values sum to unity."""
        return PSF(array=arg_0, pixel_scale=arg_0.pixel_scale, renormalize=True)


def Func(arg_0, arg_1):
        """
        Convolve an array with this PSF

        Parameters
        ----------
        image : ndarray
            An array representing the image the PSF is Funcd with.

        Returns
        -------
        Funcd_image : ndarray
            An array representing the image after convolution.

        Raises
        ------
        KernelException if either PSF psf dimension is odd
        """
        if arg_0.shape[0] % 2 == 0 or arg_0.shape[1] % 2 == 0:
            raise exc.KernelException("PSF Kernel must be odd")

        return scipy.signal.Func2d(arg_1, arg_0, mode='same')


def Func(arg_0):
        """Compute the Voronoi grid of the pixelization, using the pixel centers.

        Parameters
        ----------
        pixel_centers : ndarray
            The (y,x) centre of every Voronoi pixel.
        """
        return scipy.spatial.Voronoi(np.asarray([arg_0[:, 1], arg_0[:, 0]]).T,
                                     qhull_options='Qbb Qc Qx Qm')


def Func(arg_0, arg_1, arg_2):
        """Compute the neighbors of every Voronoi pixel as an ndarray of the pixel index's each pixel shares a \
        vertex with.

        The ridge points of the Voronoi grid are used to derive this.

        Parameters
        ----------
        ridge_points : scipy.spatial.Voronoi.ridge_points
            Each Voronoi-ridge (two indexes representing a pixel mapping_matrix).
        """
        return pixelization_util.voronoi_neighbors_from_pixels_and_ridge_points(arg_1=arg_1,
                                                                                arg_2=np.asarray(arg_2))


def Func(arg_0, arg_1, arg_2, arg_3, arg_4):
    """Set the x and y labels of the figure, and set the fontsize of those labels.

    The x and y labels are always the distance scales, thus the labels are either arc-seconds or kpc and depend on the \
    units the figure is plotted in.

    Parameters
    -----------
    units : str
        The units of the y / x axis of the plots, in arc-seconds ('arcsec') or kiloparsecs ('kpc').
    kpc_per_arcsec : float
        The conversion factor between arc-seconds and kiloparsecs, required to plot the units in kpc.
    xlabelsize : int
        The fontsize of the x axes label.
    ylabelsize : int
        The fontsize of the y axes label.
    xyticksize : int
        The font size of the x and y ticks on the figure axes.
    """
    if arg_0 in 'arcsec' or arg_1 is None:

        plt.xlabel('x (arcsec)', fontsize=arg_2)
        plt.ylabel('y (arcsec)', fontsize=arg_3)

    elif arg_0 in 'kpc':

        plt.xlabel('x (kpc)', fontsize=arg_2)
        plt.ylabel('y (kpc)', fontsize=arg_3)

    else:
        raise exc.PlottingException('The units supplied to the plotted are not a valid string (must be pixels | '
                                     'arcsec | kpc)')

    plt.tick_params(labelsize=arg_4)


def Func(arg_0):
    """
    Decorate a profile method that accepts a coordinate grid and returns a data grid.

    If an interpolator attribute is associated with the input grid then that interpolator is used to down sample the
    coordinate grid prior to calling the function and up sample the result of the function.

    If no interpolator attribute is associated with the input grid then the function is called as normal.

    Parameters
    ----------
    func
        Some method that accepts a grid

    Returns
    -------
    decorated_function
        The function with optional interpolation
    """

    @wraps(arg_0)
    def wrapper(arg_1, arg_2, arg_3=None, *arg_4, **arg_5):
        if hasattr(arg_2, "interpolator"):
            arg_6 = arg_2.interpolator
            if arg_2.interpolator is not None:
                arg_7 = arg_0(arg_1, arg_6.interp_grid, arg_3, *arg_4, **arg_5)
                if arg_7.ndim == 1:
                    return arg_6.interpolated_values_from_values(arg_7=arg_7)
                elif arg_7.ndim == 2:
                    arg_8 = arg_6.interpolated_values_from_values(arg_7=arg_7[:, 0])
                    arg_9 = arg_6.interpolated_values_from_values(arg_7=arg_7[:, 1])
                    return np.asarray([arg_8, arg_9]).T
        return arg_0(arg_1, arg_2, arg_3, *arg_4, **arg_5)

    return wrapper


def Func(arg_0, arg_1, arg_2):
        """For a padded grid-stack and psf, compute an unmasked blurred image from an unmasked unblurred image.

        This relies on using the lens data's padded-grid, which is a grid of (y,x) coordinates which extends over the \
        entire image as opposed to just the masked region.

        Parameters
        ----------
        psf : ccd.PSF
            The PSF of the image used for convolution.
        unmasked_image_1d : ndarray
            The 1D unmasked image which is blurred.
        """
        arg_3 = arg_0.regular.convolve_array_1d_with_psf(padded_array_1d=arg_2,
                                                                   arg_1=arg_1)

        return arg_0.regular.scaled_array_2d_from_array_1d(array_1d=arg_3)


def Func(arg_0, arg_1, arg_2, arg_3=2):
        """Setup a grid-stack of grid_stack from a 2D array shape, a pixel scale and a sub-grid size.

        This grid corresponds to a fully unmasked 2D array.

        Parameters
        -----------
        shape : (int, int)
            The 2D shape of the array, where all pixels are used to generate the grid-stack's grid_stack.
        pixel_scale : float
            The size of each pixel in arc seconds.
        sub_grid_size : int
            The size of a sub-pixel's sub-grid (sub_grid_size x sub_grid_size).
        """
        arg_4 = RegularGrid.from_shape_and_pixel_scale(arg_1=arg_1, arg_2=arg_2)
        arg_5 = SubGrid.Func(arg_1=arg_1, arg_2=arg_2,
                                                                    arg_3=arg_3)
        arg_6 = np.array([[0.0, 0.0]])
        return GridStack(arg_4, arg_5, arg_6)


def Func(arg_0, arg_1, arg_2, arg_3):
        """Setup a grid-stack of masked grid_stack from a mask,  sub-grid size and psf-shape.

        Parameters
        -----------
        mask : Mask
            The mask whose masked pixels the grid-stack are setup using.
        sub_grid_size : int
            The size of a sub-pixels sub-grid (sub_grid_size x sub_grid_size).
        psf_shape : (int, int)
            The shape of the PSF used in the analysis, which defines the mask's blurring-region.
        """
        arg_4 = PaddedRegularGrid.padded_grid_from_shape_psf_shape_and_pixel_scale(
            shape=arg_1.shape,
            arg_3=arg_3,
            pixel_scale=arg_1.pixel_scale)
        arg_5 = PaddedSubGrid.padded_grid_from_mask_sub_grid_size_and_psf_shape(arg_1=arg_1,
                                                                                arg_2=arg_2,
                                                                                arg_3=arg_3)
        # TODO : The blurring grid is not used when the grid mapper is called, the 0.0 0.0 stops errors inr ayT_racing
        # TODO : implement a more explicit solution
        return GridStack(regular=arg_4, sub=arg_5, blurring=np.array([[0.0, 0.0]]))


def Func(arg_0):
        """Compute the Func labels of this grid, used for plotting the x-axis ticks when visualizing a regular"""
        return np.linspace(np.min(arg_0[:, 1]), np.max(arg_0[:, 1]), 4)


def Func(arg_0, arg_1):
        """For an input sub-gridded array, map its hyper-values from the sub-gridded values to a 1D regular grid of \
        values by summing each set of each set of sub-pixels values and dividing by the total number of sub-pixels.

        Parameters
        -----------
        sub_array_1d : ndarray
            A 1D sub-gridded array of values (e.g. the intensities, surface-densities, potential) which is mapped to
            a 1d regular array.
        """
        return np.multiply(arg_0.sub_grid_fraction, arg_1.reshape(-1, arg_0.sub_grid_length).sum(axis=1))


def Func(arg_0):
        """The 1D index mappings between the regular-grid and masked sparse-grid."""

        return mapping_util.Func_from_sparse_mappings(
            regular_to_unmasked_sparse=arg_0.regular_to_unmasked_sparse,
            unmasked_sparse_to_sparse=arg_0.unmasked_sparse_to_sparse).astype('int')


def Func(arg_0, arg_1, arg_2):
        """Compute a 2D padded blurred image from a 1D padded image.

        Parameters
        ----------
        padded_image_1d : ndarray
            A 1D unmasked image which is blurred with the PSF.
        psf : ndarray
            An array describing the PSF kernel of the image.
        """
        arg_3 = arg_0.convolve_array_1d_with_psf(padded_array_1d=arg_1, arg_2=arg_2)
        return arg_0.scaled_array_2d_from_array_1d(array_1d=arg_3)


def Func(arg_0, arg_1):
        """ Map a padded 1D array of values to its padded 2D array.

        Parameters
        -----------
        padded_array_1d : ndarray
            A 1D array of values which were computed using the *PaddedRegularGrid*.
        """
        return mapping_util.map_unmasked_1d_array_to_2d_array_from_array_1d_and_shape(array_1d=arg_1,
                                                                                shape=arg_0.mask.shape)


def Func(arg_0, arg_1):
        """Determine a set of relocated grid_stack from an input set of grid_stack, by relocating their pixels based on the \
        borders.

        The blurring-grid does not have its coordinates relocated, as it is only used for computing analytic \
        light-profiles and not inversion-grid_stack.

        Parameters
        -----------
        grid_stack : GridStack
            The grid-stack, whose grid_stack coordinates are relocated.
        """
        arg_2 = arg_1.regular[arg_0]
        return GridStack(regular=arg_0.relocated_grid_from_grid_jit(grid=arg_1.regular, arg_2=arg_2),
                         sub=arg_0.relocated_grid_from_grid_jit(grid=arg_1.sub, arg_2=arg_2),
                         blurring=None,
                         pix=arg_0.relocated_grid_from_grid_jit(grid=arg_1.pix, arg_2=arg_2))


def Func(arg_0, arg_1, arg_2=None, arg_3=None, arg_4=None):
        """
        Run a fit for each galaxy from the previous phase.

        Parameters
        ----------
        data: LensData
        results: ResultsCollection
            Results from all previous phases
        mask: Mask
            The mask
        positions

        Returns
        -------
        results: HyperGalaxyResults
            A collection of results, with one item per a galaxy
        """
        arg_5 = arg_2.last.unmasked_model_image
        arg_6 = arg_2.last.constant.name_instance_tuples_for_class(g.Galaxy)

        arg_7 = copy.copy(arg_2.last)

        for arg_8, arg_9 in arg_6:
            arg_10 = arg_0.optimizer.copy_with_name_extension(arg_8)
            arg_10.variable.hyper_galaxy = g.HyperGalaxy
            arg_13 = arg_2.last.unmasked_image_for_galaxy(arg_9)
            arg_10.fit(arg_0.__class__.Analysis(arg_1, arg_5, arg_13))

            arg_14(arg_7.variable, arg_8).hyper_galaxy = arg_10.variable.hyper_galaxy
            arg_14(arg_7.constant, arg_8).hyper_galaxy = arg_10.constant.hyper_galaxy

        return arg_7


def Func(arg_0, arg_1,
                                                          arg_2):
    """Determine the mapping between every masked pixelization-grid pixel and pixelization-grid pixel. This is
    performed by checking whether each pixelization-grid pixel is within the regular-masks, and mapping the indexes.

    Parameters
    -----------
    total_sparse_pixels : int
        The total number of pixels in the pixelization grid which fall within the regular-masks.
    mask : ccd.masks.Mask
        The regular-masks within which pixelization pixels must be inside
    unmasked_sparse_grid_pixel_centres : ndarray
        The centres of the unmasked pixelization grid pixels.
    """

    arg_3 = np.zeros(arg_0)

    arg_4 = 0

    for arg_5 in range(arg_2.shape[0]):

        arg_6 = arg_2[arg_5, 0]
        arg_7 = arg_2[arg_5, 1]

        if not arg_1[arg_6, arg_7]:
            arg_3[arg_4] = arg_5
            arg_4 += 1

    return arg_3


def Func(arg_0, arg_1):
    """Use the central arc-second coordinate of every unmasked pixelization grid's pixels and mapping between each
    pixelization pixel and unmasked pixelization pixel to compute the central arc-second coordinate of every masked
    pixelization grid pixel.

    Parameters
    -----------
    unmasked_sparse_grid : ndarray
        The (y,x) arc-second centre of every unmasked pixelization grid pixel.
    sparse_to_unmasked_sparse : ndarray
        The index mapping between every pixelization pixel and masked pixelization pixel.
    """
    arg_2 = arg_1.shape[0]

    arg_3 = np.zeros((arg_2, 2))

    for arg_4 in range(arg_2):
        arg_3[arg_4, 0] = arg_0[arg_1[arg_4], 0]
        arg_3[arg_4, 1] = arg_0[arg_1[arg_4], 1]

    return arg_3


def Func(arg_0, arg_1, arg_2=(-1, -1), arg_3=0.0):
    """Resize an array to a new size around a central pixel.

    If the origin (e.g. the central pixel) of the resized array is not specified, the central pixel of the array is \
    calculated automatically. For example, a (5,5) array's central pixel is (2,2). For even dimensions the central \
    pixel is assumed to be the lower indexed value, e.g. a (6,4) array's central pixel is calculated as (2,1).

    The default origin is (-1, -1) because numba requires that the function input is the same type throughout the \
    function, thus a default 'None' value cannot be used.

    Parameters
    ----------
    array_2d : ndarray
        The 2D array that is resized.
    resized_shape : (int, int)
        The (y,x) new pixel dimension of the trimmed array.
    origin : (int, int)
        The oigin of the resized array, e.g. the central pixel around which the array is extracted.

    Returns
    -------
    ndarray
        The resized 2D array from the input 2D array.

    Examples
    --------
    array_2d = np.ones((5,5))
    resize_array = resize_array_2d(array_2d=array_2d, new_shape=(2,2), origin=(2, 2))
    """

    arg_4 = int(arg_0.shape[0]) % 2 == 0
    arg_5 = int(arg_0.shape[1]) % 2 == 0

    if arg_2 is (-1, -1):

        if arg_4:
            arg_6 = int(arg_0.shape[0] / 2)
        elif not arg_4:
            arg_6 = int(arg_0.shape[0] / 2)

        if arg_5:
            arg_7 = int(arg_0.shape[1] / 2)
        elif not arg_5:
            arg_7 = int(arg_0.shape[1] / 2)

        arg_2 = (arg_6, arg_7)

    arg_8 = np.zeros(shape=arg_1)

    if arg_4:
        arg_9 = arg_2[0] - int(arg_1[0] / 2)
        arg_10 = arg_2[0] + int((arg_1[0] / 2)) + 1
    elif not arg_4:
        arg_9 = arg_2[0] - int(arg_1[0] / 2)
        arg_10 = arg_2[0] + int((arg_1[0] / 2)) + 1

    if arg_5:
        arg_11 = arg_2[1] - int(arg_1[1] / 2)
        arg_12 = arg_2[1] + int((arg_1[1] / 2)) + 1
    elif not arg_5:
        arg_11 = arg_2[1] - int(arg_1[1] / 2)
        arg_12 = arg_2[1] + int((arg_1[1] / 2)) + 1

    for arg_13, arg_14 in enumerate(range(arg_9, arg_10)):
        for arg_15, arg_16 in enumerate(range(arg_11, arg_12)):
            if arg_14 >= 0 and arg_14 < arg_0.shape[0] and arg_16 >= 0 and arg_16 < arg_0.shape[1]:
                if arg_13 >= 0 and arg_13 < arg_1[0] and arg_15 >= 0 and arg_15 < arg_1[1]:
                    arg_8[arg_13, arg_15] = arg_0[arg_14, arg_16]
            else:
                if arg_13 >= 0 and arg_13 < arg_1[0] and arg_15 >= 0 and arg_15 < arg_1[1]:
                    arg_8[arg_13, arg_15] = arg_3

    return arg_8


def Func(arg_0, arg_1):
    """Bin up an array to coarser resolution, by binning up groups of pixels and using their mean value to determine \
     the value of the new pixel.

    If an array of shape (8,8) is input and the bin up size is 2, this would return a new array of size (4,4) where \
    every pixel was the mean of each collection of 2x2 pixels on the (8,8) array.

    If binning up the array leads to an edge being cut (e.g. a (9,9) array binned up by 2), an array is first \
    extracted around the centre of that array.

    Parameters
    ----------
    array_2d : ndarray
        The 2D array that is resized.
    new_shape : (int, int)
        The (y,x) new pixel dimension of the trimmed array.
    origin : (int, int)
        The oigin of the resized array, e.g. the central pixel around which the array is extracted.

    Returns
    -------
    ndarray
        The resized 2D array from the input 2D array.

    Examples
    --------
    array_2d = np.ones((5,5))
    resize_array = resize_array_2d(array_2d=array_2d, new_shape=(2,2), origin=(2, 2))
    """

    arg_2 = pad_2d_array_for_binning_up_with_bin_up_factor(arg_0=arg_0, arg_1=arg_1)

    arg_3 = np.zeros(shape=(arg_2.shape[0] // arg_1,
                                      arg_2.shape[1] // arg_1))

    for arg_4 in range(arg_3.shape[0]):
        for arg_5 in range(arg_3.shape[1]):
            arg_6 = 0.0
            for arg_7 in range(arg_1):
                for arg_8 in range(arg_1):
                    arg_9 = arg_4*arg_1 + arg_7
                    arg_10 = arg_5*arg_1 + arg_8
                    arg_6 += arg_2[arg_9, arg_10]

            arg_3[arg_4,arg_5] = arg_6 / (arg_1 ** 2.0)

    return arg_3


def Func(arg_0, arg_1):
        """For a given inversion mapping matrix, convolve every pixel's mapped regular with the PSF kernel.

        A mapping matrix provides non-zero entries in all elements which map two pixels to one another
        (see *inversions.mappers*).

        For example, lets take an regular which is masked using a 'cross' of 5 pixels:

        [[ True, False,  True]],
        [[False, False, False]],
        [[ True, False,  True]]

        As example mapping matrix of this cross is as follows (5 regular pixels x 3 source pixels):

        [1, 0, 0] [0->0]
        [1, 0, 0] [1->0]
        [0, 1, 0] [2->1]
        [0, 1, 0] [3->1]
        [0, 0, 1] [4->2]

        For each source-pixel, we can create an regular of its unit-surface brightnesses by mapping the non-zero
        entries back to masks. For example, doing this for source pixel 1 gives:

        [[0.0, 1.0, 0.0]],
        [[1.0, 0.0, 0.0]]
        [[0.0, 0.0, 0.0]]

        And source pixel 2:

        [[0.0, 0.0, 0.0]],
        [[0.0, 1.0, 1.0]]
        [[0.0, 0.0, 0.0]]

        We then convolve each of these regular with our PSF kernel, in 2 dimensions, like we would a normal regular. For
        example, using the kernel below:

        kernel:

        [[0.0, 0.1, 0.0]]
        [[0.1, 0.6, 0.1]]
        [[0.0, 0.1, 0.0]]

        Blurred Source Pixel 1 (we don't need to perform the convolution into masked pixels):

        [[0.0, 0.6, 0.0]],
        [[0.6, 0.0, 0.0]],
        [[0.0, 0.0, 0.0]]

        Blurred Source pixel 2:

        [[0.0, 0.0, 0.0]],
        [[0.0, 0.7, 0.7]],
        [[0.0, 0.0, 0.0]]

        Finally, we map each of these blurred regular back to a blurred mapping matrix, which is analogous to the
        mapping matrix.

        [0.6, 0.0, 0.0] [0->0]
        [0.6, 0.0, 0.0] [1->0]
        [0.0, 0.7, 0.0] [2->1]
        [0.0, 0.7, 0.0] [3->1]
        [0.0, 0.0, 0.6] [4->2]

        If the mapping matrix is sub-gridded, we perform the convolution on the fractional surface brightnesses in an
        identical fashion to above.

        Parameters
        -----------
        mapping_matrix : ndarray
            The 2D mapping matix describing how every inversion pixel maps to an datas_ pixel.
        """
        return arg_0.convolve_matrix_jit(arg_1, arg_0.image_frame_indexes,
                                        arg_0.image_frame_psfs, arg_0.image_frame_lengths)


def Func(arg_0, arg_1, arg_2='angular', arg_3=None,
                                     arg_4=None):
        """ Integrate the mass profiles's convergence profile to compute the total angular mass within an ellipse of \
        specified major axis. This is centred on the mass profile.

        The following units for mass can be specified and output:

        - Dimensionless angular units (default) - 'angular'.
        - Solar masses - 'angular' (multiplies the angular mass by the critical surface mass density)

        Parameters
        ----------
        major_axis : float
            The major-axis radius of the ellipse.
        unit_mass : str
            The units the mass is returned in (angular | angular).
        critical_surface_density : float or None
            The critical surface mass density of the strong lens configuration, which converts mass from angular \
            units to phsical units (e.g. solar masses).
        """

        arg_0.check_units_of_radius_and_critical_surface_density(
            radius=arg_1, arg_4=arg_4)

        arg_5 = arg_0.new_profile_with_units_converted(
            unit_length=arg_1.unit_length, arg_2='angular',
            arg_3=arg_3, arg_4=arg_4)

        arg_6 = dim.Mass(value=quad(arg_5.mass_integral, a=0.0, b=arg_1, args=(arg_0.axis_ratio,))[0],
                                arg_2='angular')
        return arg_6.convert(arg_2=arg_2, arg_4=arg_4)


def Func(arg_0, arg_1, arg_2):
        """Routine to integrate an elliptical light profiles - set axis ratio to 1 to compute the luminosity within a \
        circle"""
        arg_3 = arg_1 * arg_2
        return 2 * np.pi * arg_3 * arg_0.convergence_func(arg_1)


def Func(arg_0, arg_1, arg_2):
        """Calculate the mass between two circular annuli and compute the density by dividing by the annuli surface
        area.

        The value returned by the mass integral is dimensionless, therefore the density between annuli is returned in \
        units of inverse radius squared. A conversion factor can be specified to convert this to a physical value \
        (e.g. the critical surface mass density).

        Parameters
        -----------
        inner_annuli_radius : float
            The radius of the inner annulus outside of which the density are estimated.
        outer_annuli_radius : float
            The radius of the outer annulus inside of which the density is estimated.
        """
        arg_3 = (np.pi * arg_2 ** 2.0) - (np.pi * arg_1 ** 2.0)
        return (arg_0.mass_within_circle_in_units(radius=arg_2) -
                arg_0.mass_within_circle_in_units(radius=arg_1)) \
               / arg_3


def Func(arg_0):
        """Rescale the einstein radius by slope and axis_ratio, to reduce its degeneracy with other mass-profiles
        parameters"""
        return ((3 - arg_0.slope) / (1 + arg_0.axis_ratio)) * arg_0.einstein_radius ** (arg_0.slope - 1)


def Func(arg_0, arg_1):
        """ Calculate the projected convergence at a given set of arc-second gridded coordinates.

        Parameters
        ----------
        grid : grids.RegularGrid
            The grid of (y,x) arc-second coordinates the surface density is computed on.
        """

        arg_2 = np.zeros(arg_1.shape[0])

        arg_3 = arg_0.grid_to_elliptical_radii(arg_1)

        for arg_4 in range(arg_1.shape[0]):
            arg_2[arg_4] = arg_0.convergence_func(arg_3[arg_4])

        return arg_2


def Func(arg_0, arg_1, arg_2):
        """Tabulate an integral over the surface density of deflection potential of a mass profile. This is used in \
        the GeneralizedNFW profile classes to speed up the integration procedure.

        Parameters
        -----------
        grid : grids.RegularGrid
            The grid of (y,x) arc-second coordinates the potential / deflection_stacks are computed on.
        tabulate_bins : int
            The number of bins to tabulate the inner integral of this profile.
        """
        arg_3 = 1.0e-4
        arg_4 = 1.05 * np.max(arg_0.grid_to_elliptical_radii(arg_1))

        arg_5 = np.log10(arg_3)
        arg_6 = np.log10(arg_4)
        arg_7 = (arg_6 - arg_5) / (arg_2 - 1)

        return arg_3, arg_4, arg_5, arg_6, arg_7


def Func(arg_0, arg_1):
        """ Compute the intensity of the profile at a given radius.

        Parameters
        ----------
        radius : float
            The distance from the centre of the profile.
        """
        return arg_0.intensity * np.exp(
            -arg_0.sersic_constant * (((arg_1 / arg_0.effective_radius) ** (1. / arg_0.sersic_index)) - 1))


def Func(arg_0, arg_1 : arg_2.Length, arg_4='eps', arg_5=None, arg_6=None):
        """Compute the total luminosity of the galaxy's light profiles within a circle of specified radius.

        See *light_profiles.luminosity_within_circle* for details of how this is performed.

        Parameters
        ----------
        radius : float
            The radius of the circle to compute the dimensionless mass within.
        unit_luminosity : str
            The units the luminosity is returned in (eps | counts).
        exposure_time : float
            The exposure time of the observation, which converts luminosity from electrons per second units to counts.
        """
        if arg_0.has_light_profile:
            return sum(map(lambda p: p.Func(arg_1=arg_1, arg_4=arg_4,
                                                                         arg_5=arg_5, arg_6=arg_6),
                           arg_0.light_profiles))
        else:
            return None


def Func(arg_0, arg_1, arg_2='angular', arg_3=None, arg_4=None):
        """Compute the total angular mass of the galaxy's mass profiles within a circle of specified radius.

        See *profiles.mass_profiles.mass_within_circle* for details of how this is performed.

        Parameters
        ----------
        radius : float
            The radius of the circle to compute the dimensionless mass within.
        unit_mass : str
            The units the mass is returned in (angular | solMass).
        critical_surface_density : float
            The critical surface mass density of the strong lens configuration, which converts mass from angulalr \
            units to physical units (e.g. solar masses).
        """
        if arg_0.has_mass_profile:
            return sum(map(lambda p: p.Func(arg_1=arg_1, arg_2=arg_2,
                                                                   arg_3=arg_3,
                                                                   arg_4=arg_4),
                           arg_0.mass_profiles))
        else:
            return None


def Func(arg_0, arg_1='angular', arg_2=None):
        """The Einstein Mass of this galaxy, which is the sum of Einstein Radii of its mass profiles.

        If the galaxy is composed of multiple ellipitcal profiles with different axis-ratios, this Einstein Mass \
        may be inaccurate. This is because the differently oriented ellipses of each mass profile """

        if arg_0.has_mass_profile:
            return sum(
                map(lambda p: p.Func(arg_1=arg_1,
                                                       arg_2=arg_2),
                    arg_0.mass_profiles))
        else:
            return None


def Func(arg_0, arg_1, arg_2):
        """Compute a scaled galaxy hyper noise-map from a baseline noise-map.

        This uses the galaxy contribution map and the *noise_factor* and *noise_power* hyper-parameters.

        Parameters
        -----------
        noise_map : ndarray
            The observed noise-map (before scaling).
        contributions : ndarray
            The galaxy contribution map.
        """
        return arg_0.noise_factor * (arg_1 * arg_2) ** arg_0.noise_power


def Func(arg_0, arg_1, arg_2):
        """For a given 1D regular array and blurring array, convolve the two using this convolver.

        Parameters
        -----------
        image_array : ndarray
            1D array of the regular values which are to be blurred with the convolver's PSF.
        blurring_array : ndarray
            1D array of the blurring regular values which blur into the regular-array after PSF convolution.
        """
        return arg_0.convolve_jit(arg_1, arg_0.image_frame_indexes, arg_0.image_frame_psfs, arg_0.image_frame_lengths,
                                 arg_2, arg_0.blurring_frame_indexes, arg_0.blurring_frame_psfs,
                                 arg_0.blurring_frame_lengths)


def Func(arg_0, arg_1):
    """Compute the intensities of a list of galaxies from an input grid, by summing the individual intensities \
    of each galaxy's light profile.

    If the input grid is a *grids.SubGrid*, the intensites is calculated on the sub-grid and binned-up to the \
    original regular grid by taking the mean value of every set of sub-pixels.

    If no galaxies are entered into the function, an array of all zeros is returned.

    Parameters
    -----------
    grid : RegularGrid
        The grid (regular or sub) of (y,x) arc-second coordinates at the centre of every unmasked pixel which the \
        intensities are calculated on.
    galaxies : [galaxy.Galaxy]
        The galaxies whose light profiles are used to compute the surface densities.
    """
    if arg_1:
        return sum(map(lambda g: g.intensities_from_grid(arg_0), arg_1))
    else:
        return np.full((arg_0.shape[0]), 0.0)


def Func(arg_0, arg_1):
    """Compute the convergence of a list of galaxies from an input grid, by summing the individual convergence \
    of each galaxy's mass profile.

    If the input grid is a *grids.SubGrid*, the convergence is calculated on the sub-grid and binned-up to the \
    original regular grid by taking the mean value of every set of sub-pixels.

    If no galaxies are entered into the function, an array of all zeros is returned.

    Parameters
    -----------
    grid : RegularGrid
        The grid (regular or sub) of (y,x) arc-second coordinates at the centre of every unmasked pixel which the \
        convergence is calculated on.
    galaxies : [galaxy.Galaxy]
        The galaxies whose mass profiles are used to compute the convergence.
    """
    if arg_1:
        return sum(map(lambda g: g.convergence_from_grid(arg_0), arg_1))
    else:
        return np.full((arg_0.shape[0]), 0.0)


def Func(arg_0, arg_1):
    """Compute the potential of a list of galaxies from an input grid, by summing the individual potential \
    of each galaxy's mass profile.

    If the input grid is a *grids.SubGrid*, the surface-density is calculated on the sub-grid and binned-up to the \
    original regular grid by taking the mean value of every set of sub-pixels.

    If no galaxies are entered into the function, an array of all zeros is returned.

    Parameters
    -----------
    grid : RegularGrid
        The grid (regular or sub) of (y,x) arc-second coordinates at the centre of every unmasked pixel which the \
        potential is calculated on.
    galaxies : [galaxy.Galaxy]
        The galaxies whose mass profiles are used to compute the surface densities.
    """
    if arg_1:
        return sum(map(lambda g: g.potential_from_grid(arg_0), arg_1))
    else:
        return np.full((arg_0.shape[0]), 0.0)


def Func(arg_0, arg_1):
    """Compute the deflections of a list of galaxies from an input sub-grid, by summing the individual deflections \
    of each galaxy's mass profile.

    The deflections are calculated on the sub-grid and binned-up to the original regular grid by taking the mean value \
    of every set of sub-pixels.

    If no galaxies are entered into the function, an array of all zeros is returned.

    Parameters
    -----------
    sub_grid : RegularGrid
        The grid (regular or sub) of (y,x) arc-second coordinates at the centre of every unmasked pixel which the \
        deflections is calculated on.
    galaxies : [galaxy.Galaxy]
        The galaxies whose mass profiles are used to compute the surface densities.
    """
    if arg_1:
        return sum(map(lambda galaxy: galaxy.deflections_from_grid(arg_0), arg_1))
    else:
        return np.full((arg_0.shape[0], 2), 0.0)


def Func(arg_0, arg_1, arg_2,
                                                        arg_3):
    """For a fitting hyper_galaxy_image, hyper_galaxy model image, list of hyper galaxies images and model hyper galaxies, compute
    their contribution maps, which are used to compute a scaled-noise_map map. All quantities are masked 1D arrays.

    The reason this is separate from the *contributions_from_fitting_hyper_images_and_hyper_galaxies* function is that
    each hyper_galaxy image has a list of hyper galaxies images and associated hyper galaxies (one for each galaxy). Thus,
    this function breaks down the calculation of each 1D masked contribution map and returns them in the same datas
    structure (2 lists with indexes [image_index][contribution_map_index].

    Parameters
    ----------
    hyper_model_image_1d : ndarray
        The best-fit model image to the datas (e.g. from a previous analysis phase).
    hyper_galaxy_images_1d : [ndarray]
        The best-fit model image of each hyper galaxy to the datas (e.g. from a previous analysis phase).
    hyper_galaxies : [galaxy.Galaxy]
        The hyper galaxies which represent the model components used to scale the noise_map, which correspond to
        individual galaxies in the image.
    hyper_minimum_values : [float]
        The minimum value of each hyper_galaxy-image contribution map, which ensure zero's don't impact the scaled noise-map.
    """
    # noinspection PyArgumentList
    return list(map(lambda hyper_galaxy, hyper_galaxy_image_1d, hyper_minimum_value:
                    hyper_galaxy.contributions_from_model_image_and_galaxy_image(model_image=arg_0,
                                                                                galaxy_image=hyper_galaxy_image_1d,
                                                                                minimum_value=hyper_minimum_value),
                    arg_2, arg_1, arg_3))


def Func(arg_0, arg_1, arg_2):
    """For a contribution map and noise-map, use the model hyper galaxies to compute a scaled noise-map.

    Parameters
    -----------
    contribution_maps : ndarray
        The image's list of 1D masked contribution maps (e.g. one for each hyper galaxy)
    hyper_galaxies : [galaxy.Galaxy]
        The hyper galaxies which represent the model components used to scale the noise_map, which correspond to
        individual galaxies in the image.
    noise_map : ccd.NoiseMap or ndarray
        An array describing the RMS standard deviation error in each pixel, preferably in units of electrons per
        second.
    """
    arg_3 = list(map(lambda hyper_galaxy, contribution_map:
                                 hyper_galaxy.hyper_noise_from_contributions(arg_2=arg_2,
                                                                             contributions=contribution_map),
                                 arg_1, arg_0))
    return arg_2 + sum(arg_3)


def Func(arg_0):
    """Wrap the function in a function that checks whether the coordinates have been transformed. If they have not \
    been transformed then they are transformed.

    Parameters
    ----------
    func : (profiles, *args, **kwargs) -> Object
        A function that requires transformed coordinates

    Returns
    -------
        A function that can except cartesian or transformed coordinates
    """

    @wraps(arg_0)
    def wrapper(arg_1, arg_2, *arg_3, **arg_4):
        """

        Parameters
        ----------
        profile : GeometryProfile
            The profiles that owns the function
        grid : ndarray
            PlaneCoordinates in either cartesian or profiles coordinate system
        args
        kwargs

        Returns
        -------
            A value or coordinate in the same coordinate system as those passed in.
        """
        if not isinstance(arg_2, TransformedGrid):
            return arg_0(arg_1, arg_1.Func_to_reference_frame(arg_2), *arg_3, **arg_4)
        else:
            return arg_0(arg_1, arg_2, *arg_3, **arg_4)

    return wrapper


def Func(arg_0):
    """
    Caches results of a call to a grid function. If a grid that evaluates to the same byte value is passed into the same
    function of the same instance as previously then the cached result is returned.

    Parameters
    ----------
    func
        Some instance method that takes a grid as its argument

    Returns
    -------
    result
        Some result, either newly calculated or recovered from the cache
    """

    def wrapper(arg_1: arg_2, arg_3: arg_4.ndarray, *arg_6, **arg_7):
        if not hasattr(arg_1, "cache"):
            arg_1.cache = {}
        arg_9 = (arg_0.__name__, arg_3.tobytes())
        if arg_9 not in arg_1.cache:
            arg_1.cache[arg_9] = arg_0(arg_1, arg_3)
        return arg_1.cache[arg_9]

    return wrapper


def Func(arg_0):
        """ Determine the sin and cosine of the angle between the profile's ellipse and the positive x-axis, \
        counter-clockwise. """
        arg_1 = np.radians(arg_0.phi)
        return np.cos(arg_1), np.sin(arg_1)


def Func(arg_0, arg_1):
        """The angle between each angle theta on the grid and the profile, in radians.

        Parameters
        -----------
        grid_thetas : ndarray
            The angle theta counter-clockwise from the positive x-axis to each coordinate in radians.
        """
        arg_2 = np.add(arg_1, - arg_0.phi_radians)
        return np.cos(arg_2), np.sin(arg_2)


def Func(arg_0, arg_1, arg_2,
                                                   arg_3, arg_4):
    """ Compute the mappings between a set of regular-grid pixels and pixelization pixels, using information on \
    how regular pixels map to their closest pixelization pixel on the image-plane pix-grid and the pixelization's \
    pixel centres.

    To determine the complete set of regular-pixel to pixelization pixel mappings, we must pair every regular-pixel to \
    its nearest pixel. Using a full nearest neighbor search to do this is slow, thus the pixel neighbors (derived via \
    the Voronoi grid) are used to localize each nearest neighbor search via a graph search.

    Parameters
    ----------
    regular_grid : RegularGrid
        The grid of (y,x) arc-second coordinates at the centre of every unmasked pixel, which has been traced to \
        to an irregular grid via lens.
    regular_to_nearest_pix : ndarray
        A 1D array that maps every regular-grid pixel to its nearest pix-grid pixel (as determined on the unlensed \
        2D array).
    pixel_centres : ndarray
        The (y,x) centre of every Voronoi pixel in arc-seconds.
    pixel_neighbors : ndarray
        An array of length (voronoi_pixels) which provides the index of all neighbors of every pixel in \
        the Voronoi grid (entries of -1 correspond to no neighbor).
    pixel_neighbors_size : ndarray
        An array of length (voronoi_pixels) which gives the number of neighbors of every pixel in the \
        Voronoi grid.
     """

    arg_5 = np.zeros((arg_0.shape[0]))

    for arg_6 in range(arg_0.shape[0]):

        arg_7 = arg_1[arg_6]

        while True:

            arg_8 = arg_2[arg_7]

            arg_9 = (arg_0[arg_6, 0] - arg_8[0]) ** 2 + \
                                          (arg_0[arg_6, 1] - arg_8[1]) ** 2

            arg_10 = 1.0e8

            for arg_11 in range(arg_4[arg_7]):

                arg_12 = arg_3[arg_7, arg_11]

                arg_13 = (arg_0[arg_6, 0] - arg_2[arg_12, 0]) ** 2 + \
                                           (arg_0[arg_6, 1] - arg_2[arg_12, 1]) ** 2

                if arg_13 < arg_10:

                    arg_10 = arg_13
                    arg_14 = arg_11

            arg_15 = arg_3[arg_7, arg_14]
            arg_16 = arg_10

            if arg_9 <= arg_16:
                arg_5[arg_6] = arg_7
                break
            else:
                arg_7 = arg_15

    return arg_5


def Func(arg_0, arg_1, arg_2, arg_3,
                                               arg_4, arg_5):
    """ Compute the mappings between a set of sub-grid pixels and pixelization pixels, using information on \
    how the regular pixels hosting each sub-pixel map to their closest pixelization pixel on the image-plane pix-grid \
    and the pixelization's pixel centres.

    To determine the complete set of sub-pixel to pixelization pixel mappings, we must pair every sub-pixel to \
    its nearest pixel. Using a full nearest neighbor search to do this is slow, thus the pixel neighbors (derived via \
    the Voronoi grid) are used to localize each nearest neighbor search by using a graph search.

    Parameters
    ----------
    regular_grid : RegularGrid
        The grid of (y,x) arc-second coordinates at the centre of every unmasked pixel, which has been traced to \
        to an irregular grid via lens.
    regular_to_nearest_pix : ndarray
        A 1D array that maps every regular-grid pixel to its nearest pix-grid pixel (as determined on the unlensed \
        2D array).
    pixel_centres : (float, float)
        The (y,x) centre of every Voronoi pixel in arc-seconds.
    pixel_neighbors : ndarray
        An array of length (voronoi_pixels) which provides the index of all neighbors of every pixel in \
        the Voronoi grid (entries of -1 correspond to no neighbor).
    pixel_neighbors_size : ndarray
        An array of length (voronoi_pixels) which gives the number of neighbors of every pixel in the \
        Voronoi grid.
     """

    arg_6 = np.zeros((arg_0.shape[0]))

    for arg_7 in range(arg_0.shape[0]):

        arg_8 = arg_1[arg_2[arg_7]]

        while True:

            arg_9 = arg_3[arg_8]

            arg_10 = (arg_0[arg_7, 0] - arg_9[0]) ** 2 + \
                                          (arg_0[arg_7, 1] - arg_9[1]) ** 2

            arg_11 = 1.0e8

            for arg_12 in range(arg_5[arg_8]):

                arg_13 = arg_4[arg_8, arg_12]

                arg_14 = (arg_0[arg_7, 0] - arg_3[arg_13, 0]) ** 2 + \
                                           (arg_0[arg_7, 1] - arg_3[arg_13, 1]) ** 2

                if arg_14 < arg_11:
                    arg_11 = arg_14
                    arg_15 = arg_12

            arg_16 = arg_4[arg_8, arg_15]
            arg_17 = arg_11

            if arg_10 <= arg_17:
                arg_6[arg_7] = arg_8
                break
            else:
                arg_8 = arg_16

    return arg_6


def Func(arg_0, arg_1: arg_2.Length, arg_4='eps', arg_5=None,
                                          arg_6=None):
        """Integrate the light profile to compute the total luminosity within a circle of specified radius. This is \
        centred on the light profile's centre.

        The following units for mass can be specified and output:

        - Electrons per second (default) - 'eps'.
        - Counts - 'counts' (multiplies the luminosity in electrons per second by the exposure time).

        Parameters
        ----------
        radius : float
            The radius of the circle to compute the dimensionless mass within.
        unit_luminosity : str
            The units the luminosity is returned in (eps | counts).
        exposure_time : float or None
            The exposure time of the observation, which converts luminosity from electrons per second units to counts.
        """

        if not isinstance(arg_1, arg_2.Length):
            arg_1 = arg_2.Length(value=arg_1, unit_length='arcsec')

        arg_7 = arg_0.new_profile_with_units_converted(unit_length=arg_1.unit_length, arg_4=arg_4,
                                                        arg_5=arg_5, arg_6=arg_6)

        arg_8 = quad(arg_7.luminosity_integral, a=0.0, b=arg_1, args=(1.0,))[0]
        return arg_2.Luminosity(arg_8, arg_4)


def Func(arg_0, arg_1, arg_2='eps', arg_3=None,
                                           arg_4=None):
        """Integrate the light profiles to compute the total luminosity within an ellipse of specified major axis. \
        This is centred on the light profile's centre.

        The following units for mass can be specified and output:

        - Electrons per second (default) - 'eps'.
        - Counts - 'counts' (multiplies the luminosity in electrons per second by the exposure time).

        Parameters
        ----------
        major_axis : float
            The major-axis radius of the ellipse.
        unit_luminosity : str
            The units the luminosity is returned in (eps | counts).
        exposure_time : float or None
            The exposure time of the observation, which converts luminosity from electrons per second units to counts.
        """

        if not isinstance(arg_1, dim.Length):
            arg_1 = dim.Length(arg_1, 'arcsec')

        arg_5 = arg_0.new_profile_with_units_converted(unit_length=arg_1.unit_length,
                                                        arg_2=arg_2,
                                                        arg_3=arg_3, arg_4=arg_4)
        arg_6 = quad(arg_5.luminosity_integral, a=0.0, b=arg_1, args=(arg_0.axis_ratio,))[0]
        return dim.Luminosity(arg_6, arg_2)


def Func(arg_0, arg_1, arg_2):
        """Routine to integrate the luminosity of an elliptical light profile.

        The axis ratio is set to 1.0 for computing the luminosity within a circle"""
        arg_3 = arg_1 * arg_2
        return 2 * np.pi * arg_3 * arg_0.intensities_from_grid_radii(arg_1)


def Func(arg_0, arg_1):
        """Calculate the intensity of the Gaussian light profile on a grid of radial coordinates.

        Parameters
        ----------
        grid_radii : float
            The radial distance from the centre of the profile. for each coordinate on the grid.
        """
        return np.multiply(np.divide(arg_0.intensity, arg_0.sigma * np.sqrt(2.0 * np.pi)),
                           np.exp(-0.5 * np.square(np.divide(arg_1, arg_0.sigma))))


def Func(arg_0, arg_1 : arg_2.Length, arg_4='eps', arg_5=None):
        """Compute the total luminosity of all galaxies in this plane within a circle of specified radius.

        See *galaxy.light_within_circle* and *light_profiles.light_within_circle* for details \
        of how this is performed.

        Parameters
        ----------
        radius : float
            The radius of the circle to compute the dimensionless mass within.
        units_luminosity : str
            The units the luminosity is returned in (eps | counts).
        exposure_time : float
            The exposure time of the observation, which converts luminosity from electrons per second units to counts.
        """
        return list(map(lambda galaxy: galaxy.luminosity_within_circle_in_units(
            arg_1=arg_1, arg_4=arg_4, kpc_per_arcsec=arg_0.kpc_per_arcsec,
            arg_5=arg_5),
                        arg_0.galaxies))


def Func(arg_0, arg_1 : arg_2.Length, arg_4='eps',
                                                          arg_5=None):
        """
        Compute the total luminosity of all galaxies in this plane within a ellipse of specified major-axis.

        The value returned by this integral is dimensionless, and a conversion factor can be specified to convert it \
        to a physical value (e.g. the photometric zeropoint).

        See *galaxy.light_within_ellipse* and *light_profiles.light_within_ellipse* for details
        of how this is performed.

        Parameters
        ----------
        major_axis : float
            The major-axis radius of the ellipse.
        units_luminosity : str
            The units the luminosity is returned in (eps | counts).
        exposure_time : float
            The exposure time of the observation, which converts luminosity from electrons per second units to counts.
        """
        return list(map(lambda galaxy: galaxy.luminosity_within_ellipse_in_units(
            arg_1=arg_1, arg_4=arg_4, kpc_per_arcsec=arg_0.kpc_per_arcsec,
            arg_5=arg_5),
                        arg_0.galaxies))


def Func(arg_0, arg_1 : arg_2.Length, arg_4='angular',
                                                   arg_5=None):
        """Compute the total mass of all galaxies in this plane within a circle of specified radius.

        See *galaxy.angular_mass_within_circle* and *mass_profiles.angular_mass_within_circle* for details
        of how this is performed.

        Parameters
        ----------
        radius : float
            The radius of the circle to compute the dimensionless mass within.
        units_mass : str
            The units the mass is returned in (angular | solMass).
        critical_surface_density : float
            The critical surface mass density of the strong lens configuration, which converts mass from angulalr \
            units to physical units (e.g. solar masses).
        """
        return list(map(lambda galaxy: galaxy.mass_within_circle_in_units(
                        arg_1=arg_1, arg_4=arg_4, kpc_per_arcsec=arg_0.kpc_per_arcsec,
                        arg_5=arg_5),
                        arg_0.galaxies))


def Func(arg_0, arg_1 : arg_2.Length, arg_4='angular',
                                                    arg_5=None):
        """Compute the total mass of all galaxies in this plane within a ellipse of specified major-axis.

        See *galaxy.angular_mass_within_ellipse* and *mass_profiles.angular_mass_within_ellipse* for details \
        of how this is performed.

        Parameters
        ----------
        major_axis : float
            The major-axis radius of the ellipse.
        units_luminosity : str
            The units the luminosity is returned in (eps | counts).
        exposure_time : float
            The exposure time of the observation, which converts luminosity from electrons per second units to counts.
        """
        return list(map(lambda galaxy: galaxy.mass_within_ellipse_in_units(
                        arg_1=arg_1, arg_4=arg_4, kpc_per_arcsec=arg_0.kpc_per_arcsec,
                        arg_5=arg_5),
                        arg_0.galaxies))


def Func(arg_0):
        """Compute the Func labels of this grid_stack, used for plotting the x-axis ticks when visualizing an \
        image"""
        return np.linspace(np.amin(arg_0.grid_stack.regular[:, 1]), np.amax(arg_0.grid_stack.regular[:, 1]), 4)


def Func(arg_0, arg_1, arg_2):
        """This is a utility function for the function above, which performs the iteration over each plane's galaxies \
        and computes each galaxy's unmasked blurred image.

        Parameters
        ----------
        padded_grid_stack
        psf : ccd.PSF
            The PSF of the image used for convolution.
        """
        return [arg_1.unmasked_blurred_image_from_psf_and_unmasked_image(
            arg_2, arg_4) if not arg_3.has_pixelization else None for arg_3, arg_4 in
                zip(arg_0.galaxies, arg_0.image_plane_image_1d_of_galaxies)]


def Func(arg_0):
        """Trace the positions to the next plane."""
        return list(map(lambda positions, deflections: np.subtract(positions, deflections),
                        arg_0.positions, arg_0.deflections))


def Func(arg_0, arg_1, arg_2, arg_3, arg_4=(0.0, 0.0)):
        """
        Creates an instance of Array and fills it with a single value

        Parameters
        ----------
        value: float
            The value with which the array should be filled
        shape: (int, int)
            The shape of the array
        pixel_scale: float
            The scale of a pixel in arc seconds

        Returns
        -------
        array: ScaledSquarePixelArray
            An array filled with a single value
        """
        arg_5 = np.ones(arg_2) * arg_1
        return arg_0(arg_5, arg_3, arg_4)