riverine.actions
================

.. py:module:: riverine.actions


Attributes
----------

.. autoapisummary::

   riverine.actions.T
   riverine.actions.T_AWC
   riverine.actions.MultiFixedConcentration
   riverine.actions.MultiFixedVolume


Classes
-------

.. autoapisummary::

   riverine.actions.MixVolumeDep
   riverine.actions.AbstractAction
   riverine.actions.ActionWithComponents
   riverine.actions.FixedVolume
   riverine.actions.EqualConcentration
   riverine.actions.FixedConcentration
   riverine.actions.ToConcentration
   riverine.actions.FillToVolume


Module Contents
---------------

.. py:class:: MixVolumeDep(*args, **kwds)

   Bases: :py:obj:`enum.Enum`


   Create a collection of name/value pairs.

   Example enumeration:

   >>> class Color(Enum):
   ...     RED = 1
   ...     BLUE = 2
   ...     GREEN = 3

   Access them by:

   - attribute access:

     >>> Color.RED
     <Color.RED: 1>

   - value lookup:

     >>> Color(1)
     <Color.RED: 1>

   - name lookup:

     >>> Color['RED']
     <Color.RED: 1>

   Enumerations can be iterated over, and know how many members they have:

   >>> len(Color)
   3

   >>> list(Color)
   [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

   Methods can be added to enumerations, and members can have their own
   attributes -- see the documentation for details.


   .. py:attribute:: INDEPENDENT
      :value: 'independent'



   .. py:attribute:: DEPENDS
      :value: 'depends'



   .. py:attribute:: DETERMINES
      :value: 'determines'



.. py:data:: T

.. py:class:: AbstractAction

   Abstract class defining an action in a mix recipe.


   .. py:property:: name
      :type: str

      :abstractmethod:



   .. py:method:: mix_volume_effect(_cache_key=None) -> (MixVolumeDep, riverine.units.DecimalQuantity)
      :abstractmethod:


      The effect of the action on the mix volume.

      :returns: * *MixVolumeDep* -- How the mix volume affects the action.
                * *DecimalQuantity* -- If MixVolumeDep is DETERMINES, the total mix volume that the action causes.
                  If MixVolumeDep is DEPENDS, NAN.
                  If MixVolumeDep is INDEPENDENT, the total volume that the action adds.



   .. py:method:: _get_name(_cache_key=None) -> str


   .. py:method:: tx_volume(mix_vol: riverine.units.DecimalQuantity = NAN_VOL, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> riverine.units.DecimalQuantity

      The total volume transferred by the action to the sample.  May depend on the total mix volume.

      :param mix_vol: The mix volume.  Does not accept strings.



   .. py:method:: _mixlines(tablefmt: str | riverine.printing.TableFormat, mix_vol: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> riverine.units.Sequence[riverine.printing.MixLine]
      :abstractmethod:



   .. py:method:: all_components(mix_vol: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> pandas.DataFrame
      :abstractmethod:


      A dataframe containing all base components added by the action.

      :param mix_vol: The mix volume.  Does not accept strings.



   .. py:method:: with_experiment(experiment: riverine.experiments.Experiment, *, inplace: bool = True) -> T
      :abstractmethod:


      Returns a copy of the action updated from a experiment dataframe.



   .. py:method:: with_reference(reference: riverine.references.Reference, *, inplace: bool = False) -> T
      :abstractmethod:


      Returns a copy of the action updated from a reference dataframe.



   .. py:method:: dest_concentration(mix_vol: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = (), cache_key=None) -> riverine.units.DecimalQuantity

      The destination concentration added to the mix by the action.

      :raises ValueError: There is no good definition for a single destination concentration
          (the action may add multiple components).



   .. py:method:: dest_concentrations(mix_vol: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = (), cache_key=None) -> riverine.units.Sequence[riverine.units.DecimalQuantity]


   .. py:property:: components
      :type: list[riverine.components.AbstractComponent]

      :abstractmethod:



   .. py:property:: source_concentrations
      :type: list[riverine.units.DecimalQuantity]



   .. py:method:: _get_source_concentrations(_cache_key=None) -> list[riverine.units.DecimalQuantity]
      :abstractmethod:



   .. py:method:: each_volumes(mix_volume: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.units.DecimalQuantity]
      :abstractmethod:



   .. py:method:: _structure(d: dict[str, Any], experiment: riverine.experiments.Experiment) -> AbstractAction
      :classmethod:

      :abstractmethod:



   .. py:method:: _unstructure(experiment: riverine.experiments.Experiment | None) -> dict[str, Any]
      :abstractmethod:



.. py:data:: T_AWC

.. py:class:: ActionWithComponents

   Bases: :py:obj:`AbstractAction`


   Abstract class defining an action in a mix recipe.


   .. py:attribute:: __hash__


   .. py:attribute:: components
      :type:  list[riverine.components.AbstractComponent | str]


   .. py:property:: number
      :type: int



   .. py:method:: _get_number(_cache_key=None) -> int


   .. py:property:: name
      :type: str



   .. py:method:: mix_volume_effect(_cache_key=None) -> (MixVolumeDep, riverine.units.DecimalQuantity)
      :abstractmethod:


      The effect of the action on the mix volume.

      :returns: * *MixVolumeDep* -- How the mix volume affects the action.
                * *DecimalQuantity* -- If MixVolumeDep is DETERMINES, the total mix volume that the action causes.
                  If MixVolumeDep is DEPENDS, NAN.
                  If MixVolumeDep is INDEPENDENT, the total volume that the action adds.



   .. py:method:: __eq__(other: object) -> bool


   .. py:method:: with_experiment(experiment: riverine.experiments.Experiment, *, inplace: bool = True) -> T_AWC

      Returns a copy of the action updated from a experiment dataframe.



   .. py:method:: with_reference(reference: riverine.references.Reference, *, inplace: bool = False) -> T_AWC

      Returns a copy of the action updated from a reference dataframe.



   .. py:property:: source_concentrations
      :type: list[riverine.units.DecimalQuantity]



   .. py:method:: _get_source_concentrations(_cache_key=None) -> list[riverine.units.DecimalQuantity]


   .. py:method:: _unstructure(experiment: riverine.experiments.Experiment | None) -> dict[str, Any]


   .. py:method:: _structure(d: dict[str, Any], experiment: riverine.experiments.Experiment | None = None) -> ActionWithComponents
      :classmethod:



   .. py:method:: all_components_polars(mix_vol: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> pandas.DataFrame


   .. py:method:: all_components(mix_vol: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = ()) -> pandas.DataFrame

      A dataframe containing all base components added by the action.

      :param mix_vol: The mix volume.  Does not accept strings.



   .. py:method:: _compactstrs(tablefmt: str | riverine.printing.TableFormat, dconcs: riverine.units.Sequence[riverine.units.DecimalQuantity], eavols: riverine.units.Sequence[riverine.units.DecimalQuantity]) -> riverine.units.Sequence[riverine.printing.MixLine]


.. py:class:: FixedVolume

   Bases: :py:obj:`ActionWithComponents`


   An action adding one or multiple components, with a set transfer volume.

   :param components: A list of :ref:`Components`.
   :param fixed_volume: A fixed volume for the action.  Input can be a string (eg, "5 µL") or a pint Quantity.  The interpretation
                        of this depends on equal_conc.
   :param set_name: The name of the mix.  If not set, name is based on components.
   :param compact_display: If True (default), the action tries to display compactly in mix recipes.  If False, it displays
                           each component as a separate line.

   .. rubric:: Examples

   >>> from riverine.mixes import *
   >>> components = [
   ...     Component("c1", "200 nM"),
   ...     Component("c2", "200 nM"),
   ...     Component("c3", "200 nM"),
   ... ]

   >>> print(Mix([FixedVolume(components, "5 uL")], name="example"))
   Table: Mix: example, Conc: 66.67 nM, Total Vol: 15.00 µl
   <BLANKLINE>
   | Comp       | Src []    | Dest []   |   # | Ea Tx Vol   | Tot Tx Vol   | Loc   | Note   |
   |:-----------|:----------|:----------|----:|:------------|:-------------|:------|:-------|
   | c1, c2, c3 | 200.00 nM | 66.67 nM  |   3 | 5.00 µl     | 15.00 µl     |       |        |


   .. py:attribute:: fixed_volume
      :type:  riverine.units.DecimalQuantity


   .. py:attribute:: set_name
      :type:  str | None
      :value: None



   .. py:attribute:: compact_display
      :type:  bool
      :value: True



   .. py:method:: dest_concentrations(mix_vol: riverine.units.DecimalQuantity = NAN_VOL, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.units.DecimalQuantity]


   .. py:method:: each_volumes(mix_volume: riverine.units.DecimalQuantity = NAN_VOL, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.units.DecimalQuantity]


   .. py:property:: name
      :type: str



   .. py:method:: _get_name(_cache_key=None) -> str


   .. py:method:: _mixlines(tablefmt: str | riverine.printing.TableFormat, mix_vol: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.printing.MixLine]


   .. py:method:: mix_volume_effect(_cache_key=None) -> (MixVolumeDep, riverine.units.DecimalQuantity)

      The effect of the action on the mix volume.

      :returns: * *MixVolumeDep* -- How the mix volume affects the action.
                * *DecimalQuantity* -- If MixVolumeDep is DETERMINES, the total mix volume that the action causes.
                  If MixVolumeDep is DEPENDS, NAN.
                  If MixVolumeDep is INDEPENDENT, the total volume that the action adds.



.. py:class:: EqualConcentration(components: riverine.units.Sequence[riverine.components.AbstractComponent | str] | riverine.components.AbstractComponent | str, fixed_volume: str | riverine.units.DecimalQuantity, set_name: str | None = None, compact_display: bool = True, method: Literal['max_volume', 'min_volume', 'check'] | tuple[Literal['max_fill'], str] = 'min_volume', equal_conc: bool | str | None = None)

   Bases: :py:obj:`FixedVolume`


   An action adding an equal concentration of each component, without setting that concentration.

   Depending on the setting of
   `equal_conc`, it may require that the concentrations all be equal to begin with, or may treat the fixed
   transfer volume as the volume as the minimum or maximum volume to transfer, adjusting volumes of each
   strand to make this work and have them at equal destination concentrations.

   :param components: A list of :ref:`Components`.
   :param fixed_volume: A fixed volume for the action.  Input can be a string (eg, "5 µL") or a pint Quantity.  The interpretation
                        of this depends on equal_conc.
   :param set_name: The name of the mix.  If not set, name is based on components.
   :param compact_display: If True (default), the action tries to display compactly in mix recipes.  If False, it displays
                           each component as a separate line.
   :param method: If `"check"`, the action still transfers the same volume of each component, but will
                  raise a `ValueError` if this will not result in every component having the same concentration added
                  (ie, if they have different source concentrations).  If `"min_volume"`, the action will transfer *at least*
                  `fixed_volume` of each component, but will transfer more for components with lower source concentration,
                  so that the destination concentrations are all equal (but not fixed to a specific value).  If `"max_volume"`,
                  the action instead transfers *at most* `fixed_volume` of each component, tranferring less for higher
                  source concentration components.  If ('max_fill', buffer_name), the fixed volume is the maximum, while for
                  every component that is added at a lower volume, a corresponding volume of buffer is added to bring the total
                  volume of the two up to the fixed volume.
   :param >>> components = [:
   :param ...     Component("c1":
   :param "200 nM"):
   :param :
   :param ...     Component("c2":
   :param "200 nM"):
   :param :
   :param ...     Component("c3":
   :param "200 nM"):
   :param :
   :param ...     Component("c4":
   :param "100 nM"):
   :param ... ]:
   :param >>> print(Mix([EqualConcentration(components:
   :param "5 uL":
   :param method="min_volume")]:
   :param name="example")):
   :param Table:
   :type Table: Mix: example, Conc: 40.00 nM, Total Vol: 25.00 µl
   :param <BLANKLINE>:
   :param | Comp       | Src []    | Dest []   | #   | Ea Tx Vol   | Tot Tx Vol   | Loc   | Note   |:
   :param |:
   :type |: -----------|:----------|:----------|:----|:------------|:-------------|:------|:-------|
   :param | c1:
   :param c2:
   :param c3 | 200.00 nM | 40.00 nM  | 3   | 5.00 µl     | 15.00 µl     |       |        |:
   :param | c4         | 100.00 nM | 40.00 nM  | 1   | 10.00 µl    | 10.00 µl     |       |        |:
   :param >>> print(Mix([EqualConcentration(components:
   :param "5 uL":
   :param method="max_volume")]:
   :param name="example")):
   :param Table:
   :type Table: Mix: example, Conc: 40.00 nM, Total Vol: 12.50 µl
   :param <BLANKLINE>:
   :param | Comp       | Src []    | Dest []   | #   | Ea Tx Vol   | Tot Tx Vol   | Loc   | Note   |:
   :param |:
   :type |: -----------|:----------|:----------|:----|:------------|:-------------|:------|:-------|
   :param | c1:
   :param c2:
   :param c3 | 200.00 nM | 40.00 nM  | 3   | 2.50 µl     | 7.50 µl      |       |        |:
   :param | c4         | 100.00 nM | 40.00 nM  | 1   | 5.00 µl     | 5.00 µl      |       |        |:


   .. py:attribute:: __hash__


   .. py:attribute:: method
      :type:  Literal['max_volume', 'min_volume', 'check'] | tuple[Literal['max_fill'], str]
      :value: 'min_volume'



   .. py:property:: source_concentrations
      :type: list[riverine.units.DecimalQuantity]



   .. py:method:: _get_source_concentrations(_cache_key=None) -> list[riverine.units.DecimalQuantity]


   .. py:method:: each_volumes(mix_volume: riverine.units.DecimalQuantity = NAN_VOL, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.units.DecimalQuantity]


   .. py:method:: tx_volume(mix_vol: riverine.units.DecimalQuantity = NAN_VOL, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> riverine.units.DecimalQuantity

      The total volume transferred by the action to the sample.  May depend on the total mix volume.

      :param mix_vol: The mix volume.  Does not accept strings.



   .. py:method:: _mixlines(tablefmt: str | riverine.printing.TableFormat, mix_vol: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.printing.MixLine]


   .. py:method:: mix_volume_effect(_cache_key=None) -> (MixVolumeDep, riverine.units.DecimalQuantity)

      The effect of the action on the mix volume.

      :returns: * *MixVolumeDep* -- How the mix volume affects the action.
                * *DecimalQuantity* -- If MixVolumeDep is DETERMINES, the total mix volume that the action causes.
                  If MixVolumeDep is DEPENDS, NAN.
                  If MixVolumeDep is INDEPENDENT, the total volume that the action adds.



.. py:class:: FixedConcentration

   Bases: :py:obj:`ActionWithComponents`


   An action adding one or multiple components, with a set destination concentration per component (adjusting volumes).

   FixedConcentration adds a selection of components, with a specified destination concentration.

   :param components: A list of :ref:`Components`.
   :param fixed_concentration: A fixed concentration for the action.  Input can be a string (eg, "50 nM") or a pint Quantity.
   :param set_name: The name of the mix.  If not set, name is based on components.
   :param compact_display: If True (default), the action tries to display compactly in mix recipes.  If False, it displays
                           each component as a separate line.
   :param min_volume: Specifies a minimum volume that must be transferred per component.  Currently, this is for
                      validation only: it will cause a VolumeError to be raised if a volume is too low.

   :raises VolumeError: One of the volumes to transfer is less than the specified min_volume.

   .. rubric:: Examples

   >>> from riverine.mixes import *
   >>> components = [
   ...     Component("c1", "200 nM"),
   ...     Component("c2", "200 nM"),
   ...     Component("c3", "200 nM"),
   ...     Component("c4", "100 nM")
   ... ]

   >>> print(Mix([FixedConcentration(components, "20 nM")], name="example", fixed_total_volume="25 uL"))
   Table: Mix: example, Conc: 40.00 nM, Total Vol: 25.00 µl
   <BLANKLINE>
   | Comp       | Src []    | Dest []   | #   | Ea Tx Vol   | Tot Tx Vol   | Loc   | Note   |
   |:-----------|:----------|:----------|:----|:------------|:-------------|:------|:-------|
   | c1, c2, c3 | 200.00 nM | 20.00 nM  | 3   | 2.50 µl     | 7.50 µl      |       |        |
   | c4         | 100.00 nM | 20.00 nM  |     | 5.00 µl     | 5.00 µl      |       |        |
   | Buffer     |           |           |     |             | 12.50 µl     |       |        |
   | *Total:*   |           | 40.00 nM  |     |             | 25.00 µl     |       |        |


   .. py:attribute:: fixed_concentration
      :type:  riverine.units.DecimalQuantity


   .. py:attribute:: set_name
      :type:  str | None
      :value: None



   .. py:attribute:: compact_display
      :type:  bool
      :value: True



   .. py:attribute:: min_volume
      :type:  riverine.units.DecimalQuantity


   .. py:method:: dest_concentrations(mix_vol: riverine.units.DecimalQuantity = NAN_VOL, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.units.DecimalQuantity]


   .. py:method:: each_volumes(mix_volume: riverine.units.DecimalQuantity = NAN_VOL, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.units.DecimalQuantity]


   .. py:method:: _mixlines(tablefmt: str | riverine.printing.TableFormat, mix_vol: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.printing.MixLine]


   .. py:property:: name
      :type: str



   .. py:method:: mix_volume_effect(_cache_key=None) -> (MixVolumeDep, riverine.units.DecimalQuantity)

      The effect of the action on the mix volume.

      :returns: * *MixVolumeDep* -- How the mix volume affects the action.
                * *DecimalQuantity* -- If MixVolumeDep is DETERMINES, the total mix volume that the action causes.
                  If MixVolumeDep is DEPENDS, NAN.
                  If MixVolumeDep is INDEPENDENT, the total volume that the action adds.



.. py:class:: ToConcentration

   Bases: :py:obj:`ActionWithComponents`


   Add an amount of (non-mix) components to result in a fixed total concentration of each in the mix.

   An action adding an amount of components such that the concentration of each component in the mix will
   be at some target concentration.  Unlike FixedConcentration, which *adds* a certain concentration, this
   takes into account other contents of the mix, and only adds enough to reach a particular final
   concentration.


   .. py:attribute:: fixed_concentration
      :type:  riverine.units.DecimalQuantity


   .. py:attribute:: compact_display
      :type:  bool
      :value: True



   .. py:attribute:: min_volume
      :type:  riverine.units.DecimalQuantity


   .. py:method:: _othercomps(mix_vol: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None)


   .. py:method:: dest_concentrations(mix_vol: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> riverine.units.Sequence[riverine.units.DecimalQuantity]


   .. py:method:: each_volumes(mix_volume: riverine.units.DecimalQuantity = NAN_VOL, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.units.DecimalQuantity]


   .. py:method:: _mixlines(tablefmt: str | riverine.printing.TableFormat, mix_vol: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.printing.MixLine]


   .. py:method:: mix_volume_effect(_cache_key=None) -> (MixVolumeDep, riverine.units.DecimalQuantity)

      The effect of the action on the mix volume.

      :returns: * *MixVolumeDep* -- How the mix volume affects the action.
                * *DecimalQuantity* -- If MixVolumeDep is DETERMINES, the total mix volume that the action causes.
                  If MixVolumeDep is DEPENDS, NAN.
                  If MixVolumeDep is INDEPENDENT, the total volume that the action adds.



.. py:data:: MultiFixedConcentration

.. py:data:: MultiFixedVolume

.. py:class:: FillToVolume

   Bases: :py:obj:`ActionWithComponents`


   Abstract class defining an action in a mix recipe.


   .. py:attribute:: target_total_volume
      :type:  riverine.units.DecimalQuantity


   .. py:method:: dest_concentrations(mix_vol: riverine.units.DecimalQuantity = NAN_VOL, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.units.DecimalQuantity]


   .. py:method:: each_volumes(mix_volume: riverine.units.DecimalQuantity = NAN_VOL, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.units.DecimalQuantity]


   .. py:method:: _mixlines(tablefmt: str | riverine.printing.TableFormat, mix_vol: riverine.units.DecimalQuantity, actions: riverine.units.Sequence[AbstractAction] = (), _cache_key=None) -> list[riverine.printing.MixLine]


   .. py:method:: mix_volume_effect(_cache_key=None) -> (MixVolumeDep, riverine.units.DecimalQuantity)

      The effect of the action on the mix volume.

      :returns: * *MixVolumeDep* -- How the mix volume affects the action.
                * *DecimalQuantity* -- If MixVolumeDep is DETERMINES, the total mix volume that the action causes.
                  If MixVolumeDep is DEPENDS, NAN.
                  If MixVolumeDep is INDEPENDENT, the total volume that the action adds.



