libnano / primer3-py

Simple oligo analysis and primer design
https://libnano.github.io/primer3-py
GNU General Public License v2.0
157 stars 43 forks source link

Negative Tm with thermodynamic calculations #141

Closed cesimsek closed 5 months ago

cesimsek commented 6 months ago

Hi,

I am using the features in low-level thermodynamic calculations (primer3-py v2.0.3onpython=3.9.18).

Here is my workflow:

from primer3.thermoanalysis import ThermoAnalysis

for_primer='AGCTGCGTAATGACTAGGTA'

p3_args = {'PRIMER_DNA_CONC': 50,
          'PRIMER_SALT_DIVALENT': 1.5,
          'PRIMER_SALT_MONOVALENT': 50,
          'PRIMER_DNTP_CONC': 0.6,
          'PRIMER_ANNEALING_TEMP': 64
           }

mv_conc = p3_args['PRIMER_SALT_MONOVALENT']
dv_conc = p3_args['PRIMER_SALT_DIVALENT']
dntp_conc = p3_args['PRIMER_DNTP_CONC']
dna_conc = p3_args['PRIMER_DNA_CONC']
temp_c = 37
ThermoAnalysis = primer3.thermoanalysis.ThermoAnalysis
p3_therm = ThermoAnalysis(mv_conc,dv_conc,dntp_conc,dna_conc,temp_c)
p3_therm.calc_homodimer(for_primer)

I end up getting a negative Tm for the predicted structure: ThermoResult(structure_found=True, tm=-10.57, dg=-3425.80, dh=-43000.00, ds=-127.60)

As with different sequences I have the same issue, I assumed it is because I cannot set the annealing temperature correctly and I also tried: primer3.thermoanalysis.ThermoAnalysis.set_thermo_args.annealing_temp_c = 64.0

Which did not make a difference. Could you point me out what may be going wrong here? Thanks!

benpruitt commented 6 months ago

Invoking calc_homodimer as in your example is equivalent to invoking ntthal (the binary compiled directly from the primer3 source) like this:

$ ./ntthal -mv 50 -dv 1.5 -n 0.6 -d 50 -s1 AGCTGCGTAATGACTAGGTA -s2 AGCTGCGTAATGACTAGGTA -path ./primer3_config/ 
Calculated thermodynamical parameters for dimer:    dS = -127.597   dH = -43000 dG = -3425.8    t = -10.5692
SEQ AGCTGCGTAATGA    GTA----------
SEQ              CTAG             
STR              GATC             
STR           ATG    AGTAATGCGTCGA

Changing the temperature at which the duplex is calculated impacts the Gibbs free energy but not the Tm:

$ ./ntthal -mv 50 -dv 1.5 -n 0.6 -d 50 -t 64 -s1 AGCTGCGTAATGACTAGGTA -s2 AGCTGCGTAATGACTAGGTA -path ./primer3_config/
Calculated thermodynamical parameters for dimer:    dS = -127.597   dH = -43000 dG = 19.3196    t = -10.5692
SEQ AGCTGCGTAATGA    GTA----------
SEQ              CTAG             
STR              GATC             
STR           ATG    AGTAATGCGTCGA

Looks like the primer3 binary results match the primer3-py results, so this behavior is intrinsic to the primer3 library rather than the Python bindings. It also looks like a pretty weak interaction so it might be unsuriprising that the result of the nearest neighbor thermo calculation is negative.

That being said I agree it is an odd output, seems like the correct behavior should be to indicate that no structure was found under these circumstances. May be a question for the primer3 maintainers over at https://github.com/primer3-org.

By the way -- annealing_temp_c is only used for calc_tm (the primer3-py version of oligotm). Also, you are passing temp_c into the constructure of ThermoAnalysis, which has dmso_conc as the fifth positional argument. I'd suggest using the primer3.bindings.calc_homodimer method rather than creating an instance of ThermoAnalysis and then invoking the instance method.

cesimsek commented 5 months ago

Hi @benpruitt,

Thank you for the prompt response!

I realized that annealing_temp_c is indeed not used for these calculations and temp_c change indeed did not make a difference in the original issue. Also switched to primer.bindings.calc_homodimer method, thanks for the tip!

I have created an issue on the primer3 page, will update if there are news.