BioPHP - Melting Temperature (Tm) calculation
Original code submitted by josebaCode bellow is covered by GNU GPL v2 license.
Description
Last change: 2011/04/27 11:01 | Recent Changes | Original descriptionThis tool will calculate melting temperature for an oligonucleotide. Formulas are explained in the script.
Code
Last change: 2019/06/16 11:09 | Recent Changes | Download | Original code and<?php
// author Joseba Bikandi
// license GNU GPL v2
// source code available at biophp.org
// #######################################################################
// GET DATA
// #######################################################################
// GETDATA
// GET PRIMER SEQUENCE
$primer="";
$primer=strtoupper($_GET["primer"]);
// REMOVE FROM PRIMER NON CODING PARTS
$primer=preg_replace("/\W|[^ATGCYRWSKMDVHBN]|\d/","",$primer);
// SHOW ERROR WHEN LENGTH OF PRIMER IS NOT IN THE CORRECT RANGE
if ($primer!="" and (strlen($primer)<6 or strlen($primer)>50)){die("Error:<br>Length of primer must be 6-50 bp.");}
// GET ADDITIONAL DATA
$primer_concentration=200;
if($_GET["cp"]){$primer_concentration=$_GET["cp"];}
$salt_concentration=50;
if($_GET["cs"]){$salt_concentration=$_GET["cs"];}
$mg_concentration=0;
if($_GET["cmg"]){$mg_concentration=$_GET["cmg"];}
// #######################################################################
// COMPUTE WHEN PRIMER IS SUBMITTED
// #######################################################################
$basic_primer_info="";
$tm_basic="";
$tm_Base_Stacking="";
if($primer!=""){
// BASIC PRIMER INFORMATION
// in case a primer is submitted, they are shown length, C+G % and Molecular weigth
// compute length
$length=strlen($primer);
// compute C+G % (it is rounded to one decimal)
$cg=round(100*CountCG($primer)/$length,1);
// compute Molecular weigth (uses and function)
$Mol_wt=Mol_wt($primer);
//basic primer info length, C+G % and Molecular weigth
$basic_primer_info ="<table width=100%><tr><td bgcolor=DDDDFF><pre>";
$basic_primer_info.="LENGTH ".$length."\n"; // length
$basic_primer_info.="C+G% ".$cg."\n"; // C+G content
$basic_primer_info.=$Mol_wt; // Molecular weigth
$basic_primer_info.="</pre></td></tr></table>\n";
// COMPUTE TM WHEN REQUESTED
// BASIC TM
if($_GET["basic"]==1){
$tm_basic="<tr><td> </td><td bgcolor=DDDDFF><pre>";
if (strlen($primer)!=CountATCG($primer)){
// when degenerated nucleotides are included within primer sequence
// minimum and maximum tm values are computed
$tm_basic.="Minimun <font color=880000><b>".Tm_min($primer)." °C</b></font>\n";
$tm_basic.="Maximum <font color=880000><b>".Tm_max($primer)." °C</b></font>";
}else{
// when degenerated nucleotides are not present, only one tm value is computed
$tm_basic.="Tm: <font color=880000><b>".Tm_min($primer)." °C</b></font>";
}
$tm_basic.="</pre></td>";
}
// BASE STACKING TM
if($_GET["NearestNeighbor"]==1){
$tm_Base_Stacking ="<tr><td> </td><td bgcolor=DDDDFF><pre>";
$tm_Base_Stacking.=tm_Base_Stacking($primer,$primer_concentration,$salt_concentration,$mg_concentration); //
$tm_Base_Stacking.="</pre></td>";
}
}
// #######################################################################
// GENERATE RESPONSE (4output)
// #######################################################################
// PAGE TOP
$output ="<html><head><title>Melting Temperature (Tm) Calculation</title></head><body bgcolor=FFFFFF>";
$output.="<center><table border=0><tr><td>";
$output.="<center><h2>Melting Temperature (Tm) Calculation</h2></center>";
// THE FORM
// INCLUDES Tm INFORMATION WHEN REQUESTED
$output.="<form method=get action=\"".$_SERVER["PHP_SELF"]."\">";
$output.="<b>Primer </b>(6-50 bases):<br>";
$output.="<input type=text name=primer value=\"".$primer."\" size=40>"; // primer sequence will be included in the form in case it was submitted and procesed
$output.="<input type=submit value=\"Compute Tm\">";
$output.=$basic_primer_info; // output basic primer info in case it is available
$output.="<table width=100%>";
$output.="<tr>";
$output.="<td valign=top>";
$output.="<input type=checkbox name=basic value=1";if ($_GET["basic"]==1){$output.=" checked";}$output.=">";
$output.="</td>";
$output.="<td valign=top>";
$output.="<a href=?formula=basic>Basic Tm</a>";
$output.="<br><font size=-1> Degenerated nucleotides are allowed</a></font>";
$output.="</td>";
$output.=$tm_basic; // BASIC TM is computed and shown when requested
$output.="</tr>";
$output.="<tr>";
$output.="<td valign=top>";
$output.="<input type=checkbox name=NearestNeighbor value=1";if ($_GET["NearestNeighbor"]==1){$output.=" checked";}$output.=">";
$output.="</td>";
$output.="<td valign=top>";
$output.="<a href=?formula=BaseStaking>Base-Stacking Tm</a>";
$output.="<br><font size=-1> Degenerated nucleotides are NOT allowed</a></font>\n";
$output.="<table>\n";
$output.="<tr><td>Primer concentration:</td><td><input type=text name=cp value=".$primer_concentration." size=4> nM</td></tr>\n";
$output.="<tr><td>Salt concentration:</td><td><input type=text name=cs value=".$salt_concentration." size=4> mM</td></tr>\n";
$output.="<tr><td>Mg<font size=-2><sup>2+</sup></font> concentration:</td><td><input type=text name=cmg value=".$mg_concentration." size=4> mM</td></tr>\n";
$output.="</table>\n";
$output.=$tm_Base_Stacking; // BASE STACKING TM is computed and shown when requested
$output.="</td>";
$output.="</tr>";
$output.="</table>";
$output.="</form>";
$output.="<hr>";
// END FORM
// LINK TO SCRIPT
$output.="<font size=-1>\nSource code is freely downloable at <a href=http://www.biophp.org/minitools/melting_temperature/>biophp.org</a>\n</font>\n";
$output.="</td></tr></table>\n";
// INFO ABOUT TM COMPUTIG METHODS WHEN REQUESTED
// SHOW BASIC TM INFO
if ($_GET["formula"]=="basic"){
$output.=BasicTmInfo();
}
// SHOW BASE-STACKING TM
if ($_GET["formula"]=="BaseStaking"){
$output.=BaseStackingTmInfo();
}
// ENDING
$output.="</center>\n</body></html>\n";
// OUTPUT PAGE CONTENT ($output)
// OPTION 1 (sends info as normal text)
// print $output;
// OPTION 2 (sends info as gz compressed text to reduce bandwidth usage)
header("Content-Encoding: gzip");
echo gzencode($output,9);
die();
// #######################################################################
// FUNTIONS
// #######################################################################
function Tm_min($primer){
$primer2=primer_min($primer);
$n_AT=substr_count($primer2,"A");
$n_CG=substr_count($primer2,"G");
$primer_len=strlen($primer2);
return basic_tm($n_AT,$n_CG,$primer_len);
}
function Tm_max($primer){
$primer2=primer_max($primer);
$n_AT=substr_count($primer2,"A");
$n_CG=substr_count($primer2,"G");
$primer_len=strlen($primer2);
return basic_tm($n_AT,$n_CG,$primer_len);
}
function basic_tm($n_AT,$n_CG,$primer_len){
if ($primer_len < 14) {
return round(2 * ($n_AT) + 4 * ($n_CG));
}else{
return round(64.9 + 41*(($n_CG-16.4)/$primer_len),1);
}
}
function tm_Base_Stacking($c,$conc_primer,$conc_salt,$conc_mg){
if (CountATCG($c)!= strlen($c)){return "Non computed. The oligonucleotide contains degenerated nucleotides.";}
$h=$s=0;
// from table at http://www.ncbi.nlm.nih.gov/pmc/articles/PMC19045/table/T2/ (SantaLucia, 1998)
// enthalpy values
$array_h["AA"]= -7.9;
$array_h["AC"]= -8.4;
$array_h["AG"]= -7.8;
$array_h["AT"]= -7.2;
$array_h["CA"]= -8.5;
$array_h["CC"]= -8.0;
$array_h["CG"]=-10.6;
$array_h["CT"]= -7.8;
$array_h["GA"]= -8.2;
$array_h["GC"]= -9.8;
$array_h["GG"]= -8.0;
$array_h["GT"]= -8.4;
$array_h["TA"]= -7.2;
$array_h["TC"]= -8.2;
$array_h["TG"]= -8.5;
$array_h["TT"]= -7.9;
// entropy values
$array_s["AA"]=-22.2;
$array_s["AC"]=-22.4;
$array_s["AG"]=-21.0;
$array_s["AT"]=-20.4;
$array_s["CA"]=-22.7;
$array_s["CC"]=-19.9;
$array_s["CG"]=-27.2;
$array_s["CT"]=-21.0;
$array_s["GA"]=-22.2;
$array_s["GC"]=-24.4;
$array_s["GG"]=-19.9;
$array_s["GT"]=-22.4;
$array_s["TA"]=-21.3;
$array_s["TC"]=-22.2;
$array_s["TG"]=-22.7;
$array_s["TT"]=-22.2;
// effect on entropy by salt correction; von Ahsen et al 1999
// Increase of stability due to presence of Mg;
$salt_effect= ($conc_salt/1000)+(($conc_mg/1000) * 140);
// effect on entropy
$s+=0.368 * (strlen($c)-1)* log($salt_effect);
// terminal corrections. Santalucia 1998
$firstnucleotide=substr($c,0,1);
if ($firstnucleotide=="G" or $firstnucleotide=="C"){$h+=0.1; $s+=-2.8;}
if ($firstnucleotide=="A" or $firstnucleotide=="T"){$h+=2.3; $s+=4.1;}
$lastnucleotide=substr($c,strlen($c)-1,1);
if ($lastnucleotide=="G" or $lastnucleotide=="C"){$h+=0.1; $s+=-2.8;}
if ($lastnucleotide=="A" or $lastnucleotide=="T"){$h+=2.3; $s+=4.1;}
// compute new H and s based on sequence. Santalucia 1998
for($i=0; $i<strlen($c)-1; $i++){
$subc=substr($c,$i,2);
$h+=$array_h[$subc];
$s+=$array_s[$subc];
}
$tm=((1000*$h)/($s+(1.987*log($conc_primer/2000000000))))-273.15;
$result="Tm: <font color=880000><b>".round($tm,1)." °C</b></font>";
$result.="\n<font color=008800> Enthalpy: ".round($h,2)."\n Entropy: ".round($s,2)."</font>";
return $result;
}
function Mol_wt($primer){
$upper_mwt=molwt($primer,"DNA","upperlimit");
$lower_mwt=molwt($primer,"DNA","lowerlimit");
if ($upper_mwt==$lower_mwt){
return "Molecular weight: $upper_mwt";
}else{
return "Upper Molecular weight: $upper_mwt\nLower Molecular weight: $lower_mwt";
}
}
function CountCG($c){
$cg=substr_count($c,"G")+substr_count($c,"C");
return $cg;
}
function CountATCG($c){
$cg=substr_count($c,"A")+substr_count($c,"T")+substr_count($c,"G")+substr_count($c,"C");
return $cg;
}
function primer_min($primer){
$primer=preg_replace("/A|T|Y|R|W|K|M|D|V|H|B|N/","A",$primer);
$primer=preg_replace("/C|G|S/","G",$primer);
return $primer;
}
function primer_max($primer){
$primer=preg_replace("/A|T|W/","A",$primer);
$primer=preg_replace("/C|G|Y|R|S|K|M|D|V|H|B|N/","G",$primer);
return $primer;
}
function molwt($sequence,$moltype,$limit){
// the following are single strand molecular weights / base
$rna_A_wt = 329.245;
$rna_C_wt = 305.215;
$rna_G_wt = 345.245;
$rna_U_wt = 306.195;
$dna_A_wt = 313.245;
$dna_C_wt = 289.215;
$dna_G_wt = 329.245;
$dna_T_wt = 304.225;
$water = 18.015;
$dna_wts = array('A' => array($dna_A_wt, $dna_A_wt), // Adenine
'C' => array($dna_C_wt, $dna_C_wt), // Cytosine
'G' => array($dna_G_wt, $dna_G_wt), // Guanine
'T' => array($dna_T_wt, $dna_T_wt), // Thymine
'M' => array($dna_C_wt, $dna_A_wt), // A or C
'R' => array($dna_A_wt, $dna_G_wt), // A or G
'W' => array($dna_T_wt, $dna_A_wt), // A or T
'S' => array($dna_C_wt, $dna_G_wt), // C or G
'Y' => array($dna_C_wt, $dna_T_wt), // C or T
'K' => array($dna_T_wt, $dna_G_wt), // G or T
'V' => array($dna_C_wt, $dna_G_wt), // A or C or G
'H' => array($dna_C_wt, $dna_A_wt), // A or C or T
'D' => array($dna_T_wt, $dna_G_wt), // A or G or T
'B' => array($dna_C_wt, $dna_G_wt), // C or G or T
'X' => array($dna_C_wt, $dna_G_wt), // G, A, T or C
'N' => array($dna_C_wt, $dna_G_wt) // G, A, T or C
);
$rna_wts = array('A' => array($rna_A_wt, $rna_A_wt), // Adenine
'C' => array($rna_C_wt, $rna_C_wt), // Cytosine
'G' => array($rna_G_wt, $rna_G_wt), // Guanine
'U' => array($rna_U_wt, $rna_U_wt), // Uracil
'M' => array($rna_C_wt, $rna_A_wt), // A or C
'R' => array($rna_A_wt, $rna_G_wt), // A or G
'W' => array($rna_U_wt, $rna_A_wt), // A or U
'S' => array($rna_C_wt, $rna_G_wt), // C or G
'Y' => array($rna_C_wt, $rna_U_wt), // C or U
'K' => array($rna_U_wt, $rna_G_wt), // G or U
'V' => array($rna_C_wt, $rna_G_wt), // A or C or G
'H' => array($rna_C_wt, $rna_A_wt), // A or C or U
'D' => array($rna_U_wt, $rna_G_wt), // A or G or U
'B' => array($rna_C_wt, $rna_G_wt), // C or G or U
'X' => array($rna_C_wt, $rna_G_wt), // G, A, U or C
'N' => array($rna_C_wt, $rna_G_wt) // G, A, U or C
);
$all_na_wts = array('DNA' => $dna_wts, 'RNA' => $rna_wts);
//print_r($all_na_wts);
$na_wts = $all_na_wts[$moltype];
$mwt = 0;
$NA_len = strlen($sequence);
if($limit=="lowerlimit"){$wlimit=1;}
if($limit=="upperlimit"){$wlimit=0;}
for ($i = 0; $i < $NA_len; $i++) {
$NA_base = substr($sequence, $i, 1);
$mwt += $na_wts[$NA_base][$wlimit];
}
$mwt += $water;
return $mwt;
}
function BasicTmInfo(){
// info bellow will be shows when requested
$info ="<table width=700><tr><td>\n";
$info.="<hr size=3 color=blue>\n";
$info.="<h2>Basic Melting Temperature (Tm) Calculations</h2>\n";
$info.="Two standard approximation calculations are used.\n";
$info.="<ul>\n";
$info.="<li>For sequences less than 14 nucleotides\n";
$info.="the formula is:\n";
$info.="<p> Tm= (wA+xT) * 2 + (yG+zC) * 4\n";
$info.="<p> where w,x,y,z are the number of the bases A,T,G,C in the sequence, respectively.\n";
$info.="<li>For sequences longer than 13 nucleotides, the equation used is\n";
$info.="<p> Tm= 64.9 +41*(yG+zC-16.4)/(wA+xT+yG+zC)\n";
$info.="</ul>\n";
$info.="<p>When degenerated nucleotides are included in the primer sequence (Y,R,W,S,K,M,D,V,H,B or N), those nucleotides will be internally substituted prior to minimum and maximum Tm calculation.\n";
$info.="<p><pre> Example:\n";
$info.=" Primer sequence: CTCT<b>RY</b>CT<b>WS</b>CTCTCT\n";
$info.=" Sequence for minimum Tm calculation: CTCT<b>AT</b>CT<b>AG</b>CTCTCT\n";
$info.=" Sequence for maximum Tm calculation: CTCT<b>GC</b>CT<b>AG</b>CTCTCT</pre>\n";
$info.="<p><b>ASSUMPTIONS:</b>\n";
$info.="<p>Equations above assume that the annealing occurs under the standard conditions of 50 nM primer, 50 mM Na<sup><font size=-2>+</font></sup>, and pH 7.0.";
$info.="<hr size=3 color=blue>\n";
$info.="</td></tr></table>\n";
return $info;
}
function BaseStackingTmInfo(){
$info="<table width=700><tr><td>\n";
$info.="<hr size=3 color=blue>\n";
$info.="<h2>Base-Stacking Melting Temperature (Tm) Calculations</h2>\n";
$info.="This aproximation uses Thermodynamical concepts to compute T<sub>m</sub>.\n";
$info.="<p>The following references were used to develop the script:\n";
$info.="<ul>\n";
$info.="<li>SantaLucia J. A unified view of polymer, dumbbell, and oligonucleotide DNA nearest-neighbor thermodynamics. Proc Natl Acad Sci U S A. 1998 Feb 17;95(4):1460-5.";
$info.="<a href=http://www.ncbi.nlm.nih.gov/sites/entrez?Db=pubmed&Cmd=ShowDetailView&TermToSearch=9465037>NCBI</a>\n";
$info.="<li>von Ahsen N, Oellerich M, Armstrong VW, Schütz E. Application of a thermodynamic nearest-neighbor model to estimate nucleic acid stability ";
$info.="and optimize probe design: prediction of melting points of multiple mutations of apolipoprotein B-3500 and factor V with a hybridization probe genotyping ";
$info.="assay on the LightCycler. Clin Chem. 1999 Dec;45(12):2094-101.";
$info.="<a href=http://www.ncbi.nlm.nih.gov/sites/entrez?Db=pubmed&Cmd=ShowDetailView&TermToSearch=10585340>NCBI</a>\n";
$info.="</ul>\n";
$info.="<hr size=3 color=blue>\n";
$info.="</td></tr></table>\n";
return $info;
}
?>