Skip to content

ntthal

Utility Classes and Methods for NtThermoAlign

This module contains the NtThermoAlign class for submitting multiple queries to ntthal, a command line tool included with primer3. Methods include functions to open and use subprocesses, check and manipulate status, and calculate melting temperature of valid oligo sequences. The class can be optionally used as a context manager.

Examples of Calculating Melting Temperature

>>> from prymer import ntthal
>>> t = ntthal.NtThermoAlign()
>>> print(t.duplex_tm(s1="ATGC", s2="GCAT"))
-54.75042
>>> from prymer import ntthal
>>> with ntthal.NtThermoAlign() as t:
...     print(t.duplex_tm(s1="ATGC", s2="GCAT"))
-54.75042

Attributes

DIVALENT_MILLIMOLAR module-attribute

DIVALENT_MILLIMOLAR: float = 0.0

The default concentration of divalent cations in mM

DNA_NANOMOLAR module-attribute

DNA_NANOMOLAR: float = 50.0

The concentration of DNA strands in nM

DNTP_MILLIMOLAR module-attribute

DNTP_MILLIMOLAR: float = 0.0

The default concentration of deoxynycleotide triphosphate in mM

MONOVALENT_MILLIMOLAR module-attribute

MONOVALENT_MILLIMOLAR: float = 50.0

The default concentration of monovalent cations in mM

TEMPERATURE module-attribute

TEMPERATURE: float = 37.0

The default temperature at which duplex is calculated (Celsius)

Classes

NtThermoAlign

Bases: ExecutableRunner

Uses the ntthal command line tool to calculate the melting temperature of user-provided oligo sequences.

Source code in prymer/ntthal/__init__.py
class NtThermoAlign(ExecutableRunner):
    """
    Uses the `ntthal` command line tool to calculate the melting temperature of user-provided
    oligo sequences.
    """

    def __init__(
        self,
        executable: str | Path = "ntthal",
        monovalent_millimolar: float = MONOVALENT_MILLIMOLAR,
        divalent_millimolar: float = DIVALENT_MILLIMOLAR,
        dntp_millimolar: float = DNTP_MILLIMOLAR,
        dna_nanomolar: float = DNA_NANOMOLAR,
        temperature: float = TEMPERATURE,
    ):
        """
        Args:
            executable: string or Path representation of ntthal executable path
            monovalent_millimolar: concentration of monovalent cations in mM
            divalent_millimolar: concentration of divalent cations in mM
            dntp_millimolar: concentration of deoxynycleotide triphosphate in mM
            dna_nanomolar: concentration of DNA strands in nM
            temperature: temperature at which duplex is calculated (Celsius)
        """
        executable_path = ExecutableRunner.validate_executable_path(executable=executable)
        command: list[str] = [f"{executable_path}", "-r", "-i"]

        if monovalent_millimolar < 0:
            raise ValueError(f"monovalent_millimolar must be >=0, received {monovalent_millimolar}")
        if divalent_millimolar < 0:
            raise ValueError(f"divalent_millimolar must be >=0, received {divalent_millimolar}")
        if dntp_millimolar < 0:
            raise ValueError(f"dntp_millimolar must be >=0, received {dntp_millimolar}")
        if dna_nanomolar < 0:
            raise ValueError(f"dna_nanomolar must be >=0, received {dna_nanomolar}")
        if temperature < 0:
            raise ValueError(f"temperature must be >=0, received {temperature}")

        command.extend(["-mv", f"{monovalent_millimolar}"])
        command.extend(["-dv", f"{divalent_millimolar}"])
        command.extend(["-n", f"{dntp_millimolar}"])
        command.extend(["-d", f"{dna_nanomolar}"])
        command.extend(["-t", f"{temperature}"])

        super().__init__(command=command)

    def duplex_tm(self, s1: str, s2: str) -> float:
        """
        Calculates the melting temperature (Tm) of two provided oligos.

        Args:
            s1: the sequence of oligo 1 (5'->3' orientation)
            s2: the sequence of oligo 2 (5'->3' orientation)

        Example:
            >>> t = NtThermoAlign()
            >>> t.duplex_tm(s1 = "ACGT", s2 = "ACGT")
            -46.542706

        Returns:
            result: ntthal-calculated melting temperature

        Raises:
            ValueError: if ntthal result cannot be cast to a float
            RuntimeError: if underlying subprocess has already been terminated
        """
        if not self.is_alive:
            raise RuntimeError(
                "Error, trying to use a subprocess that has already been "
                f"terminated, return code {self._subprocess.returncode}"
            )
        if not s1.isalpha() or not s2.isalpha():
            raise ValueError(
                "Both input strings must be all alphabetic and non-empty, "
                f"received {s1} and {s2}"
            )

        self._subprocess.stdin.write(f"{s1},{s2}\n")
        self._subprocess.stdin.flush()  # forces the input to be sent to the underlying process.
        raw_result = self._subprocess.stdout.readline().rstrip("\r\n")
        try:
            result = float(raw_result)
        except ValueError as e:
            raise ValueError(f"Error: {e}, {raw_result} cannot be cast to float") from e

        return result

Functions

__init__
__init__(
    executable: str | Path = "ntthal",
    monovalent_millimolar: float = MONOVALENT_MILLIMOLAR,
    divalent_millimolar: float = DIVALENT_MILLIMOLAR,
    dntp_millimolar: float = DNTP_MILLIMOLAR,
    dna_nanomolar: float = DNA_NANOMOLAR,
    temperature: float = TEMPERATURE,
)

Parameters:

Name Type Description Default
executable str | Path

string or Path representation of ntthal executable path

'ntthal'
monovalent_millimolar float

concentration of monovalent cations in mM

MONOVALENT_MILLIMOLAR
divalent_millimolar float

concentration of divalent cations in mM

DIVALENT_MILLIMOLAR
dntp_millimolar float

concentration of deoxynycleotide triphosphate in mM

DNTP_MILLIMOLAR
dna_nanomolar float

concentration of DNA strands in nM

DNA_NANOMOLAR
temperature float

temperature at which duplex is calculated (Celsius)

TEMPERATURE
Source code in prymer/ntthal/__init__.py
def __init__(
    self,
    executable: str | Path = "ntthal",
    monovalent_millimolar: float = MONOVALENT_MILLIMOLAR,
    divalent_millimolar: float = DIVALENT_MILLIMOLAR,
    dntp_millimolar: float = DNTP_MILLIMOLAR,
    dna_nanomolar: float = DNA_NANOMOLAR,
    temperature: float = TEMPERATURE,
):
    """
    Args:
        executable: string or Path representation of ntthal executable path
        monovalent_millimolar: concentration of monovalent cations in mM
        divalent_millimolar: concentration of divalent cations in mM
        dntp_millimolar: concentration of deoxynycleotide triphosphate in mM
        dna_nanomolar: concentration of DNA strands in nM
        temperature: temperature at which duplex is calculated (Celsius)
    """
    executable_path = ExecutableRunner.validate_executable_path(executable=executable)
    command: list[str] = [f"{executable_path}", "-r", "-i"]

    if monovalent_millimolar < 0:
        raise ValueError(f"monovalent_millimolar must be >=0, received {monovalent_millimolar}")
    if divalent_millimolar < 0:
        raise ValueError(f"divalent_millimolar must be >=0, received {divalent_millimolar}")
    if dntp_millimolar < 0:
        raise ValueError(f"dntp_millimolar must be >=0, received {dntp_millimolar}")
    if dna_nanomolar < 0:
        raise ValueError(f"dna_nanomolar must be >=0, received {dna_nanomolar}")
    if temperature < 0:
        raise ValueError(f"temperature must be >=0, received {temperature}")

    command.extend(["-mv", f"{monovalent_millimolar}"])
    command.extend(["-dv", f"{divalent_millimolar}"])
    command.extend(["-n", f"{dntp_millimolar}"])
    command.extend(["-d", f"{dna_nanomolar}"])
    command.extend(["-t", f"{temperature}"])

    super().__init__(command=command)
duplex_tm
duplex_tm(s1: str, s2: str) -> float

Calculates the melting temperature (Tm) of two provided oligos.

Parameters:

Name Type Description Default
s1 str

the sequence of oligo 1 (5'->3' orientation)

required
s2 str

the sequence of oligo 2 (5'->3' orientation)

required
Example

t = NtThermoAlign() t.duplex_tm(s1 = "ACGT", s2 = "ACGT") -46.542706

Returns:

Name Type Description
result float

ntthal-calculated melting temperature

Raises:

Type Description
ValueError

if ntthal result cannot be cast to a float

RuntimeError

if underlying subprocess has already been terminated

Source code in prymer/ntthal/__init__.py
def duplex_tm(self, s1: str, s2: str) -> float:
    """
    Calculates the melting temperature (Tm) of two provided oligos.

    Args:
        s1: the sequence of oligo 1 (5'->3' orientation)
        s2: the sequence of oligo 2 (5'->3' orientation)

    Example:
        >>> t = NtThermoAlign()
        >>> t.duplex_tm(s1 = "ACGT", s2 = "ACGT")
        -46.542706

    Returns:
        result: ntthal-calculated melting temperature

    Raises:
        ValueError: if ntthal result cannot be cast to a float
        RuntimeError: if underlying subprocess has already been terminated
    """
    if not self.is_alive:
        raise RuntimeError(
            "Error, trying to use a subprocess that has already been "
            f"terminated, return code {self._subprocess.returncode}"
        )
    if not s1.isalpha() or not s2.isalpha():
        raise ValueError(
            "Both input strings must be all alphabetic and non-empty, "
            f"received {s1} and {s2}"
        )

    self._subprocess.stdin.write(f"{s1},{s2}\n")
    self._subprocess.stdin.flush()  # forces the input to be sent to the underlying process.
    raw_result = self._subprocess.stdout.readline().rstrip("\r\n")
    try:
        result = float(raw_result)
    except ValueError as e:
        raise ValueError(f"Error: {e}, {raw_result} cannot be cast to float") from e

    return result