Double chain thermodynamics extension¶
Calculate thermodynamics, stability, binding equilibria, melting curves, end stability, and cosolvent corrections for fully complementary DNA duplexes.
ΔH, ΔS, specified temperature ΔG and Tm for duplex formation using versioned SantaLucia 1998 nearest neighbor parameters.
For the paper sources and internal formulas of various calculations, see FAQ: Calculation basis and references for double-chain thermodynamic expansion .
1) ΔH, ΔS, ΔG and Tm of completely complementary double strands¶
- Purpose: Calculate ΔH, ΔS, ΔG and Tm of a fully complementary DNA duplex using the nearest neighbor model to quantify duplex stability at given salt concentration, strand concentration and temperature.
- Calculation method: Accumulate adjacent stacking, initiation at both ends and self-complementary symmetry terms according to SantaLucia 1998 parameters, and add
0.368 × (N−1) × ln([Na⁺]+[K⁺])toΔS; then useΔG = ΔH − TΔS/1000andTm = 1000ΔH/(ΔS + R ln(Ct/divisor)) − 273.15, where self-complementarydivisor=1, otherwise 4. - API:
dnakit.thermodynamics.nearest_neighbor(sequence[required], complement[optional], conditions[optional], config[optional]) - Input: Required 2–60 nt canonical linear DNA; optional full reverse complementary strand, temperature, Na⁺/K⁺ total salt, strand concentration, and NN parameter configuration.
- Output: Returns a
NearestNeighborResult; the example showsdelta_h_kcal_per_mol,delta_s_cal_per_k_mol,delta_g_kcal_per_mol,tm_celsius. - Example code:
from dnakit import DNASequence
from dnakit.thermodynamics import ThermodynamicConditions, nearest_neighbor
conditions = ThermodynamicConditions(
temperature_celsius=37.0,
sodium_molar=1.0,
strand_concentration_molar=1e-6,
)
result = nearest_neighbor(DNASequence("GTGCAT"), conditions=conditions)
print(result.delta_h_kcal_per_mol, result.delta_s_cal_per_k_mol)
print(round(result.delta_g_kcal_per_mol, 4), round(result.tm_celsius, 4))
- Example output:
2) Unify double-strand stability results¶
- Purpose: Check the complementary relationship between two sequences and summarize stability indicators such as ΔG and Tm to facilitate judging whether the candidate pairing is stable enough under specified conditions.
- Calculation method: The
nativepath requires the second strand to be a complete reverse complement and directly summarizes the nearest-neighbor results above; theprimer3-clipath calls the user-installedntthalto select a mismatch/dangling-end structure. Stable booleans are determined byTm > configured temperature; Primer3 paths also require a structure to be found. - API:
dnakit.thermodynamics.duplex_stability(sequence_a[required], sequence_b[required], conditions[optional], config[optional], backend[optional], adapter[optional], max_loop[optional], output_structure[optional]) - Input: Two DNA sequences are required; optional conditions, native configuration, or explicit Primer3 adapter.
- Output: Returns a
DuplexStabilityResult; the example showsfully_complementary,delta_g_kcal_per_mol,tm_celsius. - Example code:
from dnakit import DNASequence
from dnakit.thermodynamics import ThermodynamicConditions, duplex_stability
result = duplex_stability(
DNASequence("GTGCAT"),
DNASequence("ATGCAC"),
conditions=ThermodynamicConditions(
sodium_molar=1.0,
strand_concentration_molar=1e-6,
),
)
print(
result.fully_complementary,
round(result.delta_g_kcal_per_mol, 4),
round(result.tm_celsius, 4),
)
- Example output:
3) Contribution of adjacent base pairs to steps¶
- Purpose: Step by step calculate the contribution of each adjacent base pair to ΔH, ΔS and ΔG, returning a decomposition of band positions to account for the source of local stability in the duplex.
- Calculation method: Look up SantaLucia
ΔH/ΔStable for each adjacent two-base step in the sequence, calculateΔG = ΔH − TΔS/1000step by step and sum; this decomposition does not add terminal, symmetry and salt correction terms. - API:
dnakit.thermodynamics.stacking_interactions(sequence[required], temperature_celsius[optional], config[optional]) - Input: Required canonical linear DNA of at least 2 nt; optional temperature and NN parameter configuration.
- Output: Returns a
StackingResult; the example showssteps,total_delta_g_kcal_per_mol. - Example code:
from dnakit import DNASequence
from dnakit.thermodynamics import stacking_interactions
result = stacking_interactions(DNASequence("GTGCAT"), temperature_celsius=37.0)
first = result.steps[0]
print(len(result.steps), first.top_5to3, first.bottom_3to5)
print(first.delta_h_kcal_per_mol, first.delta_s_cal_per_k_mol)
print(round(result.total_delta_g_kcal_per_mol, 4))
- Example output:
4) Conditions and Na⁺/K⁺ monovalent salt¶
- Purpose: Use structured objects to uniformly record temperature, salt concentration, chain concentration and co-solvent conditions, so that different thermodynamic calculations can be reused and accurately compared in the same experimental environment.
- Calculation method: This object mainly performs value range checking and condition recording; the native nearest neighbor model only uses
[Na⁺]+[K⁺]as the total monovalent salt. TheMg²⁺, dNTP, DMSO and formamide fields are only passed to external backends or correction functions that explicitly support them. - API:
dnakit.thermodynamics.ThermodynamicConditions(temperature_celsius[optional], sodium_molar[optional], potassium_molar[optional], magnesium_molar[optional], dntp_molar[optional], strand_concentration_molar[optional], dmso_percent[optional], dmso_factor_celsius_per_percent[optional], formamide_molar[optional], salt_model[optional]) - Input: Use
mol/Lfor all concentrations; °C for temperatures. - Output: Returns
ThermodynamicConditionsand salt-corrected thermodynamic values. - Example code:
from dnakit import DNASequence
from dnakit.thermodynamics import ThermodynamicConditions, nearest_neighbor
sodium = nearest_neighbor(
DNASequence("GTGCAT"),
conditions=ThermodynamicConditions(sodium_molar=0.05, potassium_molar=0.0),
)
potassium = nearest_neighbor(
DNASequence("GTGCAT"),
conditions=ThermodynamicConditions(sodium_molar=0.0, potassium_molar=0.05),
)
print(round(sodium.tm_celsius, 4), round(potassium.tm_celsius, 4))
print(sodium.conditions.monovalent_molar)
- Example output:
5) Ka, Kd and double chain ratio¶
- Purpose: Calculate the equilibrium constants Ka, Kd and the expected double-chain ratio based on the standard free energy ΔG and chain concentration, which are used to convert thermodynamic stability into equilibrium binding amount.
- Calculation method: First obtain
ΔGfrom the nearest neighbor model, and then calculate according toKa = exp(−ΔG/RT)andKd = 1/Ka. The double-strand concentration and ratio are obtained from the positive roots of the quadratic equation of the ideal two-state mass conservation equation, and the self-complementary and non-self-complementary cases are distinguished. - API:
dnakit.thermodynamics.binding_equilibrium(sequence[required], complement[optional], conditions[optional], config[optional]) - Input: Required canonical DNA; optional fully complementary strand, temperature, monovalent salt, total oligonucleotide strand concentration, and NN configuration.
- Output: Returns a
BindingEquilibriumResult; the example showsassociation_constant_m_inverse,dissociation_constant_molar,duplex_fraction,self_complementary. - Example code:
from dnakit import DNASequence
from dnakit.thermodynamics import ThermodynamicConditions, binding_equilibrium
result = binding_equilibrium(
DNASequence("GTGCAT"),
conditions=ThermodynamicConditions(
sodium_molar=1.0,
strand_concentration_molar=1e-6,
),
)
print(f"{result.association_constant_m_inverse:.6e}")
print(f"{result.dissociation_constant_molar:.6e}")
print(round(result.duplex_fraction, 6), result.self_complementary)
- Example output:
6) Theoretical melting curve¶
- Purpose: Calculate the double-strand ratio point by point in a given temperature range, and return the theoretical melting curve and transition area, which is used to observe the double-strand dissociation trend when the temperature increases.
- Calculation method: Recalculate the nearest neighbors
ΔG,Kaand the ideal two-state double chain ratio for each input temperature; if two adjacent points span 0.5, linear interpolation is used to obtain the curve midpoint temperature. - API:
dnakit.thermodynamics.theoretical_melting_curve(sequence[required], temperatures_celsius[required], complement[optional], conditions[optional], config[optional], progress[optional]) - Input: Required DNA sequence and 2–100001 strictly increasing temperature points at 0–100 °C; optional conditions and progress callbacks.
- Output: Returns a
TheoreticalMeltingCurveResult; the example showspoints,midpoint_temperature_celsius. - Example code:
from dnakit import DNASequence
from dnakit.thermodynamics import ThermodynamicConditions, theoretical_melting_curve
progress = []
result = theoretical_melting_curve(
DNASequence("GTGCAT"),
range(0, 51, 5),
conditions=ThermodynamicConditions(
sodium_molar=1.0,
strand_concentration_molar=1e-6,
),
progress=lambda completed, total: progress.append((completed, total)),
)
print(
round(result.points[0].duplex_fraction, 6),
round(result.points[-1].duplex_fraction, 6),
)
print(round(result.midpoint_temperature_celsius or 0.0, 4), progress[-1])
- Example output:
7) 5′/3′ end stability¶
- Purpose: Calculate the free energy or related stability index of the specified window at both ends of DNA respectively, and return the endpoint difference, which is used to analyze end stability asymmetry and primer 3′ end characteristics.
- Calculation method: Take the 5′ end and 3′ end windows of equal length, and call the fully complementary nearest neighbor model respectively; compare the two
ΔG, and the end with higher value (less negative) is marked as less stable. - API:
dnakit.thermodynamics.terminal_stability(sequence[required], window_size[optional], conditions[optional], config[optional]) - Input: Required 2–60 nt canonical DNA; optional 2 to Window size, conditions and NN configuration within sequence length range.
- Output: Returns a
TerminalStabilityResult; the example showsfive_prime_sequence,five_prime_delta_g_kcal_per_mol,three_prime_sequence,three_prime_delta_g_kcal_per_mol. - Example code:
from dnakit import DNASequence
from dnakit.thermodynamics import ThermodynamicConditions, terminal_stability
result = terminal_stability(
DNASequence("AACCGGTT"),
window_size=5,
conditions=ThermodynamicConditions(
sodium_molar=1.0,
strand_concentration_molar=1e-6,
),
)
print(result.five_prime_sequence, round(result.five_prime_delta_g_kcal_per_mol, 4))
print(result.three_prime_sequence, round(result.three_prime_delta_g_kcal_per_mol, 4))
print(result.less_stable_end)
- Example output:
8) DMSO and formamide experience correction¶
- Purpose: Apply an explicit empirical correction to the base Tm based on DMSO or formamide concentration, returning the correction value and correction amount for approximate comparison of cosolvent-containing conditions.
- Calculation method: Calculate
ΔTm_DMSO = −factor × DMSO%andΔTm_formamide = (0.453 × GC fraction − 2.88) × formamide (mol/L)according to the additive empirical formula in the Primer3 manual, and then add them to the uncorrected Tm. - API:
dnakit.thermodynamics.cosolvent_tm_correction(sequence[required], uncorrected_tm_celsius[required], dmso_percent[optional], dmso_factor_celsius_per_percent[optional], formamide_molar[optional]) - Input: Required canonical DNA and uncorrected Tm; optional DMSO volume percent, correction factor per percent, and formamide molar concentration.
- Output: Returns a
CosolventCorrectionResult; the example showsdmso_delta_tm_celsius,formamide_delta_tm_celsius,corrected_tm_celsius. - Example code:
from dnakit import DNASequence
from dnakit.thermodynamics import cosolvent_tm_correction
result = cosolvent_tm_correction(
DNASequence("ACGT"),
60.0,
dmso_percent=5.0,
formamide_molar=1.0,
)
print(result.dmso_delta_tm_celsius)
print(round(result.formamide_delta_tm_celsius, 4))
print(round(result.corrected_tm_celsius, 4))
- Example output:
9) Mg²⁺, dNTP, mismatch and dangling end for Primer3 CLI¶
- Purpose: Compute Tm, hairpin, autodimer or heterodimer results under complex salt conditions through the explicit Primer3 backend to supplement structural thermodynamic analysis not covered by the native model.
- Calculation method: DNAKit only verifies the input, assembly parameters and parses the output; Tm is calculated by Primer3
oligotmexplicitly configured by the user, and hairpin/dimer is calculated byntthal. The specific thermodynamic model, Mg²⁺/dNTP handling, and mismatch/dangling-end structure choices depend on the actual Primer3 version and parameter catalog. - API:
dnakit.thermodynamics.probe_primer3(oligotm_path[optional], ntthal_path[optional], thermodynamic_parameters_path[optional]),dnakit.thermodynamics.Primer3CLIAdapter.tm(sequence[required], conditions[optional]),dnakit.thermodynamics.Primer3CLIAdapter.heterodimer(sequence_a[required], sequence_b[required], conditions[optional], max_loop[optional], output_structure[optional]) - Input: Tm required 2–36 nt canonical DNA; heterodimer required two 1–60 nt canonical DNA; optional Na⁺/K⁺, Mg²⁺, dNTP, strand concentration and structure options.
- Output:
probe_primer3returns backend information; analyses return Tm, ΔG, and structure results. - Example code:
from dnakit import DNASequence
from dnakit.thermodynamics import (
Primer3CLIAdapter,
ThermodynamicConditions,
)
conditions = ThermodynamicConditions(
sodium_molar=0.05,
magnesium_molar=0.0015,
dntp_molar=0.0006,
strand_concentration_molar=50e-9,
)
adapter = Primer3CLIAdapter(
oligotm_path="/opt/primer3/src/oligotm",
ntthal_path="/opt/primer3/src/ntthal",
thermodynamic_parameters_path="/opt/primer3/src/primer3_config",
)
tm = adapter.tm(DNASequence("GTAAAACGACGGCCAGT"), conditions=conditions)
heterodimer = adapter.heterodimer(
DNASequence("GTGCAT"),
DNASequence("ATGCAC"),
conditions=conditions,
)
print(tm.tm_celsius, heterodimer.delta_g_kcal_per_mol)
- Example output: From the documented local environment; installation differences can change the output.
Arbitrarily modified base thermodynamics are not currently supported
Modifying bases requires a parameter set that matches the specific chemical structure and adjacent environment; there is currently no public call entry and will not be silently replaced with canonical parameters.