def balance_ions(anions, cations, anion_zs=None, cation_zs=None, <EOL>anion_concs=None, cation_concs=None, rho_w=<NUM_LIT>, <EOL>method='<STR_LIT>', selected_ion=None):
anions = list(anions)<EOL>cations = list(cations)<EOL>n_anions = len(anions)<EOL>n_cations = len(cations)<EOL>ions = anions + cations<EOL>anion_charges = [i.charge for i in anions]<EOL>cation_charges = [i.charge for i in cations]<EOL>charges = anion_charges + cation_charges + [<NUM_LIT:0>]<EOL>MW_water = [<NUM_LIT>]<EOL>rho_w = rho_w/<NUM_LIT:1000> <EOL>if anion_concs is not None and cation_concs is not None:<EOL><INDENT>anion_ws = [i*<NUM_LIT>/rho_w for i in anion_concs]<EOL>cation_ws = [i*<NUM_LIT>/rho_w for i in cation_concs]<EOL>w_water = <NUM_LIT:1> - sum(anion_ws) - sum(cation_ws)<EOL>anion_MWs = [i.MW for i in anions]<EOL>cation_MWs = [i.MW for i in cations]<EOL>MWs = anion_MWs + cation_MWs + MW_water<EOL>zs = ws_to_zs(anion_ws + cation_ws + [w_water], MWs)<EOL><DEDENT>else:<EOL><INDENT>if anion_zs is None or cation_zs is None:<EOL><INDENT>raise Exception('<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>zs = anion_zs + cation_zs<EOL>zs = zs + [<NUM_LIT:1> - sum(zs)]<EOL><DEDENT><DEDENT>impacts = [zi*ci for zi, ci in zip(zs, charges)]<EOL>balance_error = sum(impacts)<EOL>if abs(balance_error) < <NUM_LIT>:<EOL><INDENT>anion_zs = zs[<NUM_LIT:0>:n_anions]<EOL>cation_zs = zs[n_anions:n_cations+n_anions]<EOL>z_water = zs[-<NUM_LIT:1>]<EOL>return anions, cations, anion_zs, cation_zs, z_water<EOL><DEDENT>if '<STR_LIT>' in method:<EOL><INDENT>anion_zs, cation_zs, z_water = ion_balance_dominant(impacts,<EOL>balance_error, charges, zs, n_anions, n_cations, method)<EOL>return anions, cations, anion_zs, cation_zs, z_water<EOL><DEDENT>elif '<STR_LIT>' in method:<EOL><INDENT>anion_zs, cation_zs, z_water = ion_balance_proportional(<EOL>anion_charges, cation_charges, zs, n_anions, n_cations,<EOL>balance_error, method)<EOL>return anions, cations, anion_zs, cation_zs, z_water<EOL><DEDENT>elif method == '<STR_LIT>':<EOL><INDENT>increase = True<EOL>if balance_error < <NUM_LIT:0>:<EOL><INDENT>selected_ion = pubchem_db.search_name('<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>selected_ion = pubchem_db.search_name('<STR_LIT>')<EOL><DEDENT><DEDENT>elif method == '<STR_LIT>':<EOL><INDENT>increase = False<EOL>if balance_error > <NUM_LIT:0>:<EOL><INDENT>selected_ion = pubchem_db.search_name('<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>selected_ion = pubchem_db.search_name('<STR_LIT>')<EOL><DEDENT><DEDENT>elif method == '<STR_LIT>':<EOL><INDENT>increase = None<EOL><DEDENT>elif method == '<STR_LIT>':<EOL><INDENT>increase = True<EOL><DEDENT>elif method == '<STR_LIT>':<EOL><INDENT>increase = False<EOL><DEDENT>elif method == '<STR_LIT>':<EOL><INDENT>increase = True<EOL>if balance_error < <NUM_LIT:0>:<EOL><INDENT>selected_ion = selected_ion[<NUM_LIT:1>]<EOL><DEDENT>else:<EOL><INDENT>selected_ion = selected_ion[<NUM_LIT:0>]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>raise Exception('<STR_LIT>')<EOL><DEDENT>if selected_ion is None:<EOL><INDENT>raise Exception("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>anion_zs, cation_zs, z_water = ion_balance_adjust_wrapper(charges, zs, n_anions, n_cations,<EOL>anions, cations, selected_ion, increase=increase)<EOL>return anions, cations, anion_zs, cation_zs, z_water<EOL>
r'''Performs an ion balance to adjust measured experimental ion 
    compositions to electroneutrality. Can accept either the actual mole 
    fractions of the ions, or their concentrations in units of [mg/L] as well
    for convinience.

    The default method will locate the most prevalent ion in the type of 
    ion not in excess - and increase it until the two ion types balance.

    Parameters
    ----------
    anions : list(ChemicalMetadata)
        List of all negatively charged ions measured as being in the solution;
        ChemicalMetadata instances or simply objects with the attributes `MW` 
        and `charge`, [-]
    cations : list(ChemicalMetadata)
        List of all positively charged ions measured as being in the solution;
        ChemicalMetadata instances or simply objects with the attributes `MW` 
        and `charge`, [-]
    anion_zs : list, optional
        Mole fractions of each anion as measured in the aqueous solution, [-]
    cation_zs : list, optional
        Mole fractions of each cation as measured in the aqueous solution, [-]
    anion_concs : list, optional
        Concentrations of each anion in the aqueous solution in the units often
        reported (for convinience only) [mg/L]
    cation_concs : list, optional
        Concentrations of each cation in the aqueous solution in the units 
        often reported (for convinience only) [mg/L]
    rho_w : float, optional
        Density of the aqueous solutionr at the temperature and pressure the
        anion and cation concentrations were measured (if specified), [kg/m^3]
    method : str, optional
        The method to use to balance the ionimbalance; one of 'dominant', 
        'decrease dominant', 'increase dominant',
        'proportional insufficient ions increase', 
        'proportional excess ions decrease', 
        'proportional cation adjustment', 'proportional anion adjustment', 
        'Na or Cl increase', 'Na or Cl decrease', 'adjust', 'increase', 
        'decrease', 'makeup'].
    selected_ion : ChemicalMetadata, optional
        Some methods adjust only one user-specified ion; this is that input.
        For the case of the 'makeup' method, this is a tuple of (anion, cation)
        ChemicalMetadata instances and only the ion type not in excess will be
        used.

    Returns
    -------
    anions : list(ChemicalMetadata)
        List of all negatively charged ions measured as being in the solution;
        ChemicalMetadata instances after potentially adding in an ion which
        was not present but specified by the user, [-]
    cations : list(ChemicalMetadata)
        List of all positively charged ions measured as being in the solution;
        ChemicalMetadata instances after potentially adding in an ion which
        was not present but specified by the user, [-]
    anion_zs : list,
        Mole fractions of each anion in the aqueous solution after the charge
        balance, [-]
    cation_zs : list
        Mole fractions of each cation in the aqueous solution after the charge
        balance, [-]
    z_water : float
        Mole fraction of the water in the solution, [-]

    Notes
    -----
    The methods perform the charge balance as follows:

    * 'dominant' : The ion with the largest mole fraction in solution has its
      concentration adjusted up or down as necessary to balance the solution.
    * 'decrease dominant' : The ion with the largest mole fraction in the type
      of ion with *excess* charge has its own mole fraction decreased to balance
      the solution.
    * 'increase dominant' : The ion with the largest mole fraction in the type
      of ion with *insufficient* charge has its own mole fraction decreased to 
      balance the solution.
    * 'proportional insufficient ions increase' : The ion charge type which is
      present insufficiently has each of the ions mole fractions *increased*
      proportionally until the solution is balanced.
    * 'proportional excess ions decrease' :  The ion charge type which is
      present in excess has each of the ions mole fractions *decreased*
      proportionally until the solution is balanced.
    * 'proportional cation adjustment' : All *cations* have their mole fractions
      increased or decreased proportionally as necessary to balance the 
      solution.
    * 'proportional anion adjustment' : All *anions* have their mole fractions
      increased or decreased proportionally as necessary to balance the 
      solution.
    * 'Na or Cl increase' : Either Na+ or Cl- is *added* to the solution until
      the solution is balanced; the species will be added if they were not
      present initially as well.
    * 'Na or Cl decrease' : Either Na+ or Cl- is *removed* from the solution 
      until the solution is balanced; the species will be added if they were 
      not present initially as well.
    * 'adjust' : An ion specified with the parameter `selected_ion` has its
      mole fraction *increased or decreased* as necessary to balance the 
      solution. An exception is raised if the specified ion alone cannot 
      balance the solution.
    * 'increase' : An ion specified with the parameter `selected_ion` has its
      mole fraction *increased* as necessary to balance the 
      solution. An exception is raised if the specified ion alone cannot 
      balance the solution.
    * 'decrease' : An ion specified with the parameter `selected_ion` has its
      mole fraction *decreased* as necessary to balance the 
      solution. An exception is raised if the specified ion alone cannot 
      balance the solution.
    * 'makeup' : Two ions ase specified as a tuple with the parameter 
      `selected_ion`. Whichever ion type is present in the solution 
      insufficiently is added; i.e. if the ions were Mg+2 and Cl-, and there
      was too much negative charge in the solution, Mg+2 would be added until
      the solution was balanced.

    Examples
    --------
    >>> anions_n = ['Cl-', 'HCO3-', 'SO4-2']
    >>> cations_n = ['Na+', 'K+', 'Ca+2', 'Mg+2']
    >>> cations = [pubchem_db.search_name(i) for i in cations_n]
    >>> anions = [pubchem_db.search_name(i) for i in anions_n]
    >>> an_res, cat_res, an_zs, cat_zs, z_water = balance_ions(anions, cations,
    ... anion_zs=[0.02557, 0.00039, 0.00026], cation_zs=[0.0233, 0.00075,
    ... 0.00262, 0.00119], method='proportional excess ions decrease')
    >>> an_zs
    [0.02557, 0.00039, 0.00026]
    >>> cat_zs
    [0.01948165456267761, 0.0006270918850647299, 0.0021906409851594564, 0.0009949857909693717]
    >>> z_water
    0.9504856267761288

    References
    ----------