Example #1
0
/**
* $outfile will be overwritten with a data structure suitable for
*   sortable_table.php; see that code for documentation.
* $snapfile will be overwritten with an HTML snapshot of the unsorted table;
*   if null, this will be skipped.
* $resout is the file name for the table of residue analysis required for horiz
*   chart. if null, this will be skipped.
* $clash    is the data structure from loadClashlist()
* $rama     is the data structure from loadRamachandran()
* $rota     is the data structure from loadRotamer()
* $cbdev    is the data structure from loadCbetaDev()
* $pperp    is the data structure from loadBasePhosPerp()
* $suites   is the data structure from loadSuitenameReport()
* Any of them can be set to null if the data is unavailable.
*/
function writeMulticritChart($infile, $outfile, $snapfile, $resout, $clash, $rama, $rota, $cbdev, $pperp, $suites, $bbonds, $bangles, $cablam, $omega, $outliersOnly = false, $doHtmlTable = true, $cleanupAltloc = true)
{
    $startTime = time();
    //{{{ Process validation data
    // Make sure all residues are represented, and in the right order.
    $res = listResidues($infile);
    //foreach($res as $k => $v)
    //{
    //  echo $k.$v."\n";
    //}
    $alts = mapAlternates($res);
    //foreach($alts as $k => $v)
    //{
    //  foreach($alts[$k] as $i => $j)
    //  {
    //    echo $k.$j."\n";
    //  }
    //}
    $Bfact = listResidueBfactors($infile);
    $Bfact = $Bfact['res'];
    $orderIndex = 0;
    // used to maintain original PDB order on sorting.
    foreach ($res as $k => $v) {
        $res[$k] = array('cnit' => $v, 'order' => $orderIndex++, 'resHiB' => $Bfact[$v]);
    }
    $cell_color_mild = '#ffb3cc';
    $cell_color_bad = '#ff76a9';
    //this is used for all xxx_isbad not set otherwise
    $cell_color_severe = '#ee4d4d';
    if (is_array($clash)) {
        $with = $clash['clashes-with'];
        foreach ($clash['clashes'] as $cnit => $worst) {
            $res[$cnit]['clash_val'] = $worst;
            $res[$cnit]['clash'] = sprintf("%.2f", $worst) . "&Aring;<br><small>" . $with[$cnit]['srcatom'] . " with " . $with[$cnit]['dstcnit'] . " " . $with[$cnit]['dstatom'] . "</small>";
            $res[$cnit]['clash_isbad'] = true;
            $res[$cnit]['any_isbad'] = true;
            if ($res[$cnit]['clash_val'] < 0.5) {
                $res[$cnit]['clash_color'] = $cell_color_mild;
            } elseif ($res[$cnit]['clash_val'] > 0.9) {
                $res[$cnit]['clash_color'] = $cell_color_severe;
            }
            //$res[$cnit]['clash_color'] = '#ff3333';
            //echo "clash ".$cnit."\n";
        }
    }
    //}}}
    if (is_array($rama)) {
        foreach ($rama as $item) {
            $res[$item['resName']]['rama_val'] = $item['scorePct'];
            $phipsi = sprintf("%.1f,%.1f", $item['phi'], $item['psi']);
            if (isset($item['type'])) {
                if ($item['eval'] == "OUTLIER") {
                    $res[$item['resName']]['rama'] = "{$item['eval']} ({$item['scorePct']})%)<br><small>{$item['type']} / {$phipsi}</small>";
                    $res[$item['resName']]['rama_isbad'] = true;
                    $res[$item['resName']]['any_isbad'] = true;
                    // ensures that all outliers sort to the top, b/c 0.2 is a Gly outlier but not a General outlier
                    $res[$item['resName']]['rama_val'] -= 100.0;
                } elseif ($item['eval'] == "Allowed") {
                    $res[$item['resName']]['rama'] = "{$item['eval']} ({$item['scorePct']}%)<br><small>{$item['type']} / {$phipsi}</small>";
                    $res[$item['resName']]['rama_isbad'] = true;
                    $res[$item['resName']]['any_isbad'] = true;
                    $res[$item['resName']]['rama_color'] = $cell_color_mild;
                    // ensures that all outliers sort to the top, b/c 0.2 is a Gly outlier but not a General outlier
                    //$res[$item['resName']]['rama_val'] -= 100.0;
                    $res[$item['resName']]['rama_val'] -= 50.0;
                } else {
                    $res[$item['resName']]['rama'] = "{$item['eval']} ({$item['scorePct']}%)<br><small>{$item['type']} / {$phipsi}</small>";
                }
            }
        }
    }
    //}}}
    if (is_array($rota)) {
        foreach ($rota as $item) {
            $res[$item['resName']]['rota_val'] = $item['scorePct'];
            #if($item['scorePct'] <= 1.0)
            if ($item['eval'] == 'OUTLIER') {
                $res[$item['resName']]['rota'] = "{$item['eval']} ({$item['scorePct']}%)<br><small>chi angles: " . formatChiAngles($item) . "</small>";
                $res[$item['resName']]['rota_isbad'] = true;
                $res[$item['resName']]['any_isbad'] = true;
                $res[$item['resName']]['rota_val'] -= 100.0;
                //sorting hack
            } elseif ($item['eval'] == 'Allowed') {
                $res[$item['resName']]['rota'] = "{$item['eval']} ({$item['scorePct']}%) <i>{$item['rotamer']}</i><br><small>chi angles: " . formatChiAngles($item) . "</small>";
                $res[$item['resName']]['rota_color'] = $cell_color_mild;
                $res[$item['resName']]['rota_val'] -= 50.0;
                //sorting hack
            } else {
                $res[$item['resName']]['rota'] = "{$item['eval']} ({$item['scorePct']}%) <i>{$item['rotamer']}</i><br><small>chi angles: " . formatChiAngles($item) . "</small>";
            }
        }
    }
    //}}}
    if (is_array($cablam)) {
        //note: sorting keys off of cablam_val
        foreach ($cablam as $item) {
            $outlierType = trim($item['outlierType']);
            if ($outlierType == "CaBLAM Outlier") {
                $res[$item['resName']]['cablam'] = "{$item['outlierType']} ({$item['cablamScore']}%)<br><small>{$item['secStruc']}</small>";
                $res[$item['resName']]['cablam_val'] = "{$item['cablamScore']}";
                $res[$item['resName']]['any_isbad'] = true;
                $res[$item['resName']]['cablam_isbad'] = true;
                //$res[$item['resName']]['cablam_color'] = '#ff6699';
            } elseif ($outlierType == "CaBLAM Disfavored") {
                $res[$item['resName']]['cablam'] = "{$item['outlierType']} ({$item['cablamScore']}%)<br><small>{$item['secStruc']}</small>";
                $res[$item['resName']]['cablam_val'] = "{$item['cablamScore']}";
                $res[$item['resName']]['any_isbad'] = true;
                $res[$item['resName']]['cablam_isbad'] = true;
                $res[$item['resName']]['cablam_color'] = $cell_color_mild;
            } elseif ($outlierType == "CA Geom Outlier") {
                $res[$item['resName']]['cablam'] = "{$item['outlierType']} ({$item['caGeomScore']}%)";
                $res[$item['resName']]['cablam_val'] = "{$item['caGeomScore']}";
                $res[$item['resName']]['any_isbad'] = true;
                $res[$item['resName']]['cablam_isbad'] = true;
                //$res[$item['resName']]['cablam_color'] = '#999999';//dark grey
                $res[$item['resName']]['cablam_color'] = $cell_color_severe;
            } else {
                $secStruc = ltrim(trim($item['secStruc']), 'try');
                $res[$item['resName']]['cablam'] = "Favored ({$item['cablamScore']}%)<br><small>{$secStruc}</small>";
                $res[$item['resName']]['cablam_val'] = "{$item['cablamScore']}";
            }
        }
    }
    //}}}
    if (is_array($cbdev)) {
        foreach ($cbdev as $item) {
            $res[$item['resName']]['cbdev_val'] = $item['dev'];
            if ($item['dev'] >= 0.25) {
                $res[$item['resName']]['cbdev'] = sprintf("%.2f", $item['dev']) . "&Aring;";
                $res[$item['resName']]['cbdev_isbad'] = true;
                $res[$item['resName']]['any_isbad'] = true;
                if ($item['dev'] >= 0.7) {
                    $res[$item['resName']]['cbdev_color'] = $cell_color_severe;
                }
            } else {
                if ($res[$item['resName']]['cbdev'] == null) {
                    //for fixing a bug where an ok alt conf dev would get reported instead of the bad dev.
                    $res[$item['resName']]['cbdev'] = sprintf("%.2f", $item['dev']) . "&Aring;";
                }
            }
        }
    }
    //}}}
    if (is_array($omega)) {
        foreach ($omega as $item) {
            if ($item['conf'] == 'Cis') {
                $res[$item['resName']]['any_isbad'] = true;
                if ($item['type'] == 'General') {
                    $res[$item['resName']]['omega'] = "{$item['conf']} nonPRO<br><small>omega= {$item['omega']}</small>";
                    $res[$item['resName']]['omega_val'] = "1";
                    //for column sort
                    $res[$item['resName']]['omega_isbad'] = true;
                } elseif ($item['type'] == 'Pro') {
                    $res[$item['resName']]['omega'] = "{$item['conf']} PRO<br><small>omega= {$item['omega']}</small>";
                    $res[$item['resName']]['omega_val'] = "2";
                    //for column sort
                }
            } elseif ($item['conf'] == 'Twisted') {
                $res[$item['resName']]['any_isbad'] = true;
                $res[$item['resName']]['omega_isbad'] = true;
                if ($item['type'] == 'General') {
                    $res[$item['resName']]['omega'] = "{$item['conf']} nonPRO<br><small>omega= {$item['omega']}</small>";
                    $res[$item['resName']]['omega_val'] = "1";
                } elseif ($item['type'] == 'Pro') {
                    $res[$item['resName']]['omega'] = "{$item['conf']} PRO<br><small>omega= {$item['omega']}</small>";
                    $res[$item['resName']]['omega_val'] = "1";
                }
                //for column sort
            }
        }
    }
    //}}}
    if (is_array($pperp)) {
        foreach ($pperp as $item) {
            if ($item['outlier']) {
                //echo "pperp ".$item['resName']."\n";
                $reasons = array();
                if ($item['deltaOut'] && $item['epsilonOut']) {
                    $reasons[] = "&delta; & &epsilon; outlier <br><small>(P-perp distance implies {$item['probpucker']})</small>";
                } elseif ($item['deltaOut']) {
                    $reasons[] = "&delta; outlier <br><small>(P-perp distance implies {$item['probpucker']})</small>";
                } elseif ($item['epsilonOut']) {
                    $reasons[] = "&epsilon; outlier <br><small>(P-perp distance implies {$item['probpucker']})</small>";
                }
                $res[$item['resName']]['pperp_val'] = 1;
                // no way to quantify this
                $res[$item['resName']]['pperp'] = "suspect sugar pucker  -  " . implode(", ", $reasons) . "";
                $res[$item['resName']]['pperp_isbad'] = true;
                $res[$item['resName']]['any_isbad'] = true;
            }
        }
    }
    //}}}
    if (is_array($suites)) {
        foreach ($suites as $cnit => $item) {
            $res[$cnit]['suites_val'] = $item['suiteness'];
            $bin = "&delta;-1&delta;&gamma; {$item['bin']}";
            if ($bin == '&delta;-1&delta;&gamma; trig') {
                $bin = "&delta;-1&delta;&gamma; none (triaged  {$item['triage']}  )";
                $res[$cnit]['suites_val'] = -1;
                // sorts to very top
            } elseif ($bin == '&delta;-1&delta;&gamma; inc ') {
                $bin = '&delta;-1&delta;&gamma; none (incomplete)';
                $res[$cnit]['suites_val'] = 0.0001;
                // sorts just below all outliers
            } elseif (preg_match('/7D dist/', $item['triage'])) {
                $bin = "{$bin} ( {$item['triage']} )";
            }
            //echo $cnit."\n";
            if ($item['isOutlier']) {
                $res[$cnit]['suites'] = "OUTLIER<br><small>{$bin}</small>";
                $res[$cnit]['suites_isbad'] = true;
                $res[$cnit]['any_isbad'] = true;
            } elseif ($item['bin'] == 'inc ') {
                $res[$cnit]['suites'] = "conformer: {$item['conformer']}<br><small>{$bin}</small>";
            } else {
                $res[$cnit]['suites'] = "conformer: {$item['conformer']}<br><small>{$bin}, suiteness = " . sprintf("%.2f", $item[suiteness]) . "</small>";
            }
        }
    }
    //}}}
    if (is_array($bbonds)) {
        //{{{
        foreach ($bbonds as $cnit => $item) {
            if ($item['isOutlier']) {
                $res[$cnit]['bbonds_val'] = abs($item['sigma']);
                $res[$cnit]['bbonds'] = "{$item['count']} OUTLIER(S)<br><small>worst is {$item['measure']}: " . sprintf("%.1f", $item[sigma]) . " &sigma;</small>";
                $res[$cnit]['bbonds_isbad'] = true;
                $res[$cnit]['any_isbad'] = true;
                if ($res[$cnit]['bbonds_val'] >= 10) {
                    $res[$cnit]['bbonds_color'] = $cell_color_severe;
                }
            }
        }
    }
    //}}}
    if (is_array($bangles)) {
        //{{{
        foreach ($bangles as $cnit => $item) {
            if ($item['isOutlier']) {
                $res[$cnit]['bangles_val'] = abs($item['sigma']);
                $res[$cnit]['bangles'] = "{$item['count']} OUTLIER(S)<br><small>worst is {$item['measure']}: " . sprintf("%.1f", $item[sigma]) . " &sigma;</small>";
                $res[$cnit]['bangles_isbad'] = true;
                $res[$cnit]['any_isbad'] = true;
                if ($res[$cnit]['bangles_val'] >= 10) {
                    $res[$cnit]['bangles_color'] = $cell_color_severe;
                }
            }
        }
    }
    //}}}
    //}}} Process validation data
    //echo "Processing validation data took ".(time() - $startTime)." seconds\n";
    //{{{check for alternates
    foreach ($res as $cnit => $current) {
        $altloc = substr($cnit, 7, 1);
        if ($altloc != ' ') {
            $b_key = substr($cnit, 0, 7) . ' ' . substr($cnit, 8, 3);
            if (isset($res[$b_key])) {
                //{{{clash
                if (!isset($res[$cnit]['clash'])) {
                    $res[$cnit]['clash_val'] = $res[$b_key]['clash_val'];
                    $res[$cnit]['clash'] = $res[$b_key]['clash'];
                    $res[$cnit]['clash_isbad'] = $res[$b_key]['clash_isbad'];
                    $res[$cnit]['any_isbad'] = $res[$b_key]['any_isbad'];
                }
                //}}}
                //{{{rama
                if (!isset($res[$cnit]['rama'])) {
                    $res[$cnit]['rama_val'] = $res[$b_key]['rama_val'];
                    $res[$cnit]['rama'] = $res[$b_key]['rama'];
                    if (isset($res[$b_key]['rama_isbad'])) {
                        $res[$cnit]['rama_isbad'] = $res[$b_key]['rama_isbad'];
                        $res[$cnit]['any_isbad'] = $res[$b_key]['any_isbad'];
                    }
                }
                //}}}
                //{{{rota
                if (!isset($res[$cnit]['rota'])) {
                    $res[$cnit]['rota_val'] = $res[$b_key]['rota_val'];
                    $res[$cnit]['rota'] = $res[$b_key]['rota'];
                    if (isset($res[$b_key]['rota_isbad'])) {
                        $res[$cnit]['rota_isbad'] = $res[$b_key]['rota_isbad'];
                        $res[$cnit]['any_isbad'] = $res[$b_key]['any_isbad'];
                    }
                }
                //}}}
                //{{{cbdev
                if (!isset($res[$cnit]['cbdev_val'])) {
                    $res[$cnit]['cbdev_val'] = $res[$b_key]['cbdev_val'];
                    $res[$cnit]['cbdev'] = $res[$b_key]['cbdev'];
                    if (isset($res[$b_key]['rama_isbad'])) {
                        $res[$cnit]['cbdev_isbad'] = $res[$b_key]['cbdev_isbad'];
                        $res[$cnit]['any_isbad'] = $res[$b_key]['any_isbad'];
                    }
                }
                //}}}
                //{{{pperp
                if (!isset($res[$cnit]['pperp'])) {
                    if (isset($res[$b_key]['pperp'])) {
                        $res[$cnit]['pperp_val'] = $res[$b_key]['pperp_val'];
                        $res[$cnit]['pperp'] = $res[$b_key]['pperp'];
                        $res[$cnit]['pperp_isbad'] = $res[$b_key]['pperp_isbad'];
                        $res[$cnit]['any_isbad'] = $res[$b_key]['any_isbad'];
                    }
                }
                //}}}
                //{{{suites
                if (!isset($res[$cnit]['suites'])) {
                    $res[$cnit]['suites_val'] = $res[$b_key]['suites_val'];
                    $res[$cnit]['suites'] = $res[$b_key]['suites'];
                    if (isset($res[$b_key]['suites_isbad'])) {
                        $res[$cnit]['suites_isbad'] = $res[$b_key]['suites_isbad'];
                        $res[$cnit]['any_isbad'] = $res[$b_key]['any_isbad'];
                    }
                }
                //}}}
                //{{{bbonds
                if (!isset($res[$cnit]['bbonds'])) {
                    if (isset($res[$b_key]['bbonds_isbad'])) {
                        $res[$cnit]['bbonds_val'] = $res[$b_key]['bbonds_val'];
                        $res[$cnit]['bbonds'] = $res[$b_key]['bbonds'];
                        $res[$cnit]['bbonds_isbad'] = $res[$b_key]['bbonds_isbad'];
                        $res[$cnit]['any_isbad'] = $res[$b_key]['any_isbad'];
                    }
                }
                //}}}
                //{{{bangles
                if (!isset($res[$cnit]['bangles'])) {
                    if (isset($res[$b_key]['bangles_isbad'])) {
                        $res[$cnit]['bangles_val'] = $res[$b_key]['bangles_val'];
                        $res[$cnit]['bangles'] = $res[$b_key]['bangles'];
                        $res[$cnit]['bangles_isbad'] = $res[$b_key]['bangles_isbad'];
                        $res[$cnit]['any_isbad'] = $res[$b_key]['any_isbad'];
                    }
                }
                //}}}
                //{{{omega
                if (isset($res[$cnit]['omega'])) {
                    if (isset($res[$b_key]['omega_isbad'])) {
                        $res[$cnit]['omega_val'] = $res[$b_key]['omega_val'];
                        $res[$cnit]['omega'] = $res[$b_key]['omega'];
                        $res[$cnit]['omega_isbad'] = $res[$b_key]['omega_isbad'];
                        $res[$cnit]['any_isbad'] = $res[$b_key]['any_isbad'];
                    }
                }
                //}}}
                //{{{Bfactor
                if (isset($res[$b_key]['resHiB'])) {
                    $res[$cnit]['resHiB'] = max($res[$cnit]['resHiB'], $res[$b_key]['resHiB']);
                }
                //}}}
                //{{{CaBLAM
                if (isset($res[$cnit]['cablam'])) {
                    if (isset($res[$b_key]['cablam_isbad'])) {
                        $res[$cnit]['cablam_val'] = $res[$b_key]['cablam_val'];
                        $res[$cnit]['cablam'] = $res[$b_key]['cablam'];
                        $res[$cnit]['cablam_isbad'] = $res[$b_key]['cablam_isbad'];
                    }
                }
                //}}}
            }
        }
    }
    //}}}
    //remove redundant ' ' entries for residues with alternates
    if ($cleanupAltloc) {
        foreach ($alts as $cnit => $alt) {
            foreach ($alts[$cnit] as $i => $j) {
                $b_key = substr($cnit, 0, 7) . ' ' . substr($cnit, 8, 3);
                unset($res[$b_key]);
            }
        }
    }
    //foreach ($bbonds as $cnit => $alt)
    //{
    //  echo $bbonds[$cnit]['resName']."\n";
    //}
    // $res needs to be saved in raw_data for the horoizontal chart
    if ($resout) {
        $out = fopen($resout, 'wb');
        fwrite($out, mpSerialize($res));
        fclose($out);
    }
    // Set up output data structure
    $table = array('prequel' => '', 'headers' => array(), 'rows' => array(), 'footers' => array(), 'sequel' => '');
    $startTime = time();
    //{{{ Table prequel and headers
    // Do summary chart
    $pdbstats = pdbstat($infile);
    $table['prequel'] = makeSummaryStatsTable($pdbstats['resolution'], $clash, $rama, $rota, $cbdev, $pperp, $suites, $bbonds, $bangles, $cablam, $omega);
    if ($doHtmlTable) {
        $header1 = array();
        $header1[] = array('html' => "<b>#</b>", 'sort' => 1);
        $header1[] = array('html' => "<b>Alt</b>", 'sort' => 1);
        $header1[] = array('html' => "<b>Res</b>", 'sort' => 1);
        $header1[] = array('html' => "<b>High B</b>", 'sort' => -1);
        if (is_array($clash)) {
            $header1[] = array('html' => "<b>Clash &gt; 0.4&Aring;</b>", 'sort' => -1);
        }
        if (is_array($rama)) {
            $header1[] = array('html' => "<b>Ramachandran</b>", 'sort' => 1);
        }
        if (is_array($rota)) {
            $header1[] = array('html' => "<b>Rotamer</b>", 'sort' => 1);
        }
        if (is_array($cbdev)) {
            $header1[] = array('html' => "<b>C&beta; deviation</b>", 'sort' => -1);
        }
        if (is_array($cablam)) {
            $header1[] = array('html' => "<b>CaBLAM</b>", 'sort' => 1);
        }
        if (is_array($pperp)) {
            $header1[] = array('html' => "<b>Base-P perp. dist.</b>", 'sort' => -1);
        }
        if (is_array($suites)) {
            $header1[] = array('html' => "<b>RNA suite conf.</b>", 'sort' => 1);
        }
        if (is_array($bbonds)) {
            $header1[] = array('html' => "<b>Bond lengths</b>", 'sort' => -1);
        }
        if (is_array($bangles)) {
            $header1[] = array('html' => "<b>Bond angles</b>", 'sort' => -1);
        }
        if (is_array($omega)) {
            $header1[] = array('html' => "<b>Cis Peptides</b>", 'sort' => 1);
        }
        $header2 = array();
        $header2[] = array('html' => "");
        $header2[] = array('html' => "");
        $header2[] = array('html' => "");
        $header2[] = array('html' => sprintf("Avg: %.2f", array_sum($Bfact) / count($Bfact)));
        if (is_array($clash)) {
            $header2[] = array('html' => "Clashscore: {$clash['scoreAll']}");
        }
        if (is_array($rama)) {
            $header2[] = array('html' => "Outliers: " . count(findRamaOutliers($rama)) . " of " . findAltTotal($rama));
        }
        if (is_array($rota)) {
            $header2[] = array('html' => "Poor rotamers: " . count(findRotaOutliers($rota)) . " of " . findAltTotal($rota));
        }
        if (is_array($cbdev)) {
            $header2[] = array('html' => "Outliers: " . count(findCbetaOutliers($cbdev)) . " of " . findAltTotal($cbdev));
        }
        if (is_array($cablam)) {
            $header2[] = array('html' => "Outliers: " . count(findCablamOutliers($cablam)) . " of " . findAltTotal($cablam));
        }
        if (is_array($pperp)) {
            $header2[] = array('html' => "Outliers: " . count(findBasePhosPerpOutliers($pperp)) . " of " . findAltTotal($pperp));
        }
        if (is_array($suites)) {
            $header2[] = array('html' => "Outliers: " . count(findSuitenameOutliers($suites)) . " of " . findAltTotal($suites));
        }
        if (is_array($bbonds)) {
            $header2[] = array('html' => "Outliers: " . count(findGeomOutliers($bbonds)) . " of " . findAltTotal($bbonds));
        }
        if (is_array($bangles)) {
            $header2[] = array('html' => "Outliers: " . count(findGeomOutliers($bangles)) . " of " . findAltTotal($bangles));
        }
        if (is_array($omega)) {
            $header2[] = array('html' => "Non-Trans: " . count(findOmegaOutliers($omega)) . " of " . findAltTotal($omega));
        }
        $table['headers'] = array($header1, $header2);
    }
    //}}} Table prequel and headers
    //echo "Table prequel and headers took ".(time() - $startTime)." seconds\n";
    $startTime = time();
    //{{{ Table body
    if ($doHtmlTable) {
        $rows = array();
        foreach ($res as $cnit => $eval) {
            if ($outliersOnly && !$eval['any_isbad']) {
                continue;
            }
            if (!$_SESSION['useSEGID']) {
                $cni = substr($cnit, 0, 7);
                $alt = substr($cnit, 7, 1);
                $type = substr($cnit, 8, 3);
            } else {
                $cni = substr($cnit, 0, 9);
                $alt = substr($cnit, 9, 1);
                $type = substr($cnit, 10, 3);
            }
            //$cni = "'".$cni."'";
            $row = array();
            //$row[] = array('html' => $cnit,             'sort_val' => $eval['order']+0);
            $row[] = array('html' => $cni, 'sort_val' => $eval['order'] + 0);
            $row[] = array('html' => $alt, 'sort_val' => $alt);
            $row[] = array('html' => $type, 'sort_val' => $type);
            $row[] = array('html' => $eval['resHiB'], 'sort_val' => $eval['resHiB'] + 0);
            foreach (array('clash', 'rama', 'rota', 'cbdev', 'cablam', 'pperp', 'suites', 'bbonds', 'bangles', 'omega') as $type) {
                if (is_array(${$type})) {
                    $cell = array();
                    if (isset($eval[$type])) {
                        $cell['html'] = $eval[$type];
                    } else {
                        $cell['html'] = "-";
                    }
                    if (isset($eval[$type . '_color'])) {
                        $cell['color'] = $eval[$type . '_color'];
                    } elseif (isset($eval[$type . '_isbad'])) {
                        $cell['color'] = $cell_color_bad;
                    }
                    if (isset($eval[$type . '_val'])) {
                        $cell['sort_val'] = $eval[$type . '_val'] + 0;
                    }
                    $row[] = $cell;
                }
            }
            /*
            if(is_array($clash))
            $row[] = array('html' => (isset($eval['clash']) ? $eval['clash'] : "-"),        'sort_val' => $eval['clash_val']+0);
            if(is_array($rama))
            $row[] = array('html' => (isset($eval['rama']) ? $eval['rama'] : "-"),          'sort_val' => $eval['rama_val']+0);
            if(is_array($rota))
            $row[] = array('html' => (isset($eval['rota']) ? $eval['rota'] : "-"),          'sort_val' => $eval['rota_val']+0);
            if(is_array($cbdev))
            $row[] = array('html' => (isset($eval['cbdev']) ? $eval['cbdev'] : "-"),        'sort_val' => $eval['cbdev_val']+0);
            if(is_array($pperp))
            $row[] = array('html' => (isset($eval['pperp']) ? $eval['pperp'] : "-"),        'sort_val' => $eval['pperp_val']+0);
            */
            $rows[] = $row;
        }
        $table['rows'] = $rows;
    }
    //}}} Table body
    //echo "Table body took ".(time() - $startTime)." seconds\n";
    $startTime = time();
    $out = fopen($outfile, 'wb');
    fwrite($out, mpSerialize($table));
    fclose($out);
    //echo "Serializing table took ".(time() - $startTime)." seconds\n";
    // serialize() and unserialize() screw up floating point numbers sometimes.
    // Not only is there a change in precision, but sometimes numbers become INF
    // in some versions of PHP 4, like those shipped with Mac OS X.
    //
    #$tmpfile = $_SESSION['dataDir'].'/'.MP_DIR_RAWDATA.'/table_dump';
    #$out = fopen($tmpfile.'1', 'wb');
    #fwrite($out, var_export($table, true));
    #fclose($out);
    #$time = time();
    #    $out = fopen($tmpfile.'2', 'wb');
    #    fwrite($out, var_export(unserialize(serialize($table)), true));
    #    fclose($out);
    #echo "Dump+load time for serialize: ".(time() - $time)." seconds\n";
    #$time = time();
    #    $out = fopen($tmpfile.'3', 'wb');
    #    fwrite($out, var_export(eval("return ".var_export($table, true).";"), true));
    #    fclose($out);
    #echo "Dump+load time for var_export: ".(time() - $time)." seconds\n";
    # WAY TOO SLOW (all in PHP, no C code):
    #$time = time();
    #    $json = new Services_JSON();
    #    $out = fopen($tmpfile.'4', 'wb');
    #    fwrite($out, var_export($json->decode($json->encode($table)), true));
    #    fclose($out);
    #echo "Dump+load time for JSON: ".(time() - $time)." seconds\n";
    if ($snapfile) {
        $startTime = time();
        $out = fopen($snapfile, 'wb');
        //fwrite($out, formatSortableTable($table, 'DUMMY_URL'));
        fwrite($out, formatSortableTableJS($table));
        fclose($out);
        //echo "Formatting sortable table took ".(time() - $startTime)." seconds\n";
    }
}
Example #2
0
/**
* This is the uber-validation function that calls everything below.
* It is suited for use from either the web or command line interface.
* This only makes sense in terms of an active session.
*   modelID             ID code for model to process
*   opts                has the following keys mapped to boolean flags:
*     doKinemage        make the multi-criterion kinemage at all?
*       kinClashes      show clash dots?
*       kinHbonds       show H-bond dots?
*       kinContacts     show contact dots?
*       kinRama         show Rama outliers?
*       kinRota         show rotamer outliers?
*       kinGeom         show bond length and angle outliers?
*       kinCBdev        show C-beta deviations?
*       kinBaseP        show base-phosphate perpendiculars?
*       kinSuite        show RNA backbone conformational outliers?
*       kinAltConfs     show alternate conformations?
*       kinBfactor      show B-factor color model?
*       kinOccupancy    show occupancy color model?
*       kinRibbons      show ribbons?
*       kinForceViews   force running clashlist, etc to provide @views of bad spots?
*     doCharts          make the multi-criterion chart and other plots/tables/lists?
*       chartClashlist  run clashlistcluster?
*       chartRama       do Rama plots and analysis?
*       chartRota       do rotamer analysis?
*       chartGeom       do bond length and angle outliers?
*       chartCBdev      do CB dev plots and analysis?
*       chartBaseP      check base-phosphate perpendiculars?
*       chartSuite      check RNA backbone conformations?
*       chartHoriz      do horizontal chart?
*       chartCoot       do coot chart?
*       chartMulti      do html multi chart?
*       chartNotJustOut include residues that have no problems in the list?
*       chartAltloc     remove redundant residue rows when altlocs present?
*       chartImprove    compare to reduce -(no)build results to show improvement?
*
* This function returns some HTML suitable for using in a lab notebook entry.
*/
function runAnalysis($modelID, $opts)
{
    //{{{ Set up file/directory vars and the task list
    // If doKinemage or doCharts is off, turn off all their subordinates
    if (!$opts['doKinemage']) {
        foreach ($opts as $k => $v) {
            if (startsWith($k, 'kin')) {
                $opts[$k] = false;
            }
        }
    }
    if (!$opts['doCharts']) {
        foreach ($opts as $k => $v) {
            if (startsWith($k, 'chart')) {
                $opts[$k] = false;
            }
        }
    }
    if ($opts['kinForceViews']) {
        foreach ($opts as $k => $v) {
            if (startsWith($k, 'chart')) {
                $opts[$k] = true;
            }
        }
    }
    $model = $_SESSION['models'][$modelID];
    $modelDir = $_SESSION['dataDir'] . '/' . MP_DIR_MODELS;
    $modelURL = $_SESSION['dataURL'] . '/' . MP_DIR_MODELS;
    $kinDir = $_SESSION['dataDir'] . '/' . MP_DIR_KINS;
    $kinURL = $_SESSION['dataURL'] . '/' . MP_DIR_KINS;
    if (!file_exists($kinDir)) {
        mkdir($kinDir, 0777);
    }
    $rawDir = $_SESSION['dataDir'] . '/' . MP_DIR_RAWDATA;
    if (!file_exists($rawDir)) {
        mkdir($rawDir, 0777);
    }
    $chartDir = $_SESSION['dataDir'] . '/' . MP_DIR_CHARTS;
    $chartURL = $_SESSION['dataURL'] . '/' . MP_DIR_CHARTS;
    if (!file_exists($chartDir)) {
        mkdir($chartDir, 0777);
    }
    $xrayDir = $_SESSION['dataDir'] . '/' . MP_DIR_XRAYDATA;
    $infile = "{$modelDir}/{$model['pdb']}";
    $reduce_blength = $_SESSION['reduce_blength'];
    if (isset($model['mtz_file'])) {
        $mtz_file = $model['mtz_file'];
    } else {
        $mtz_file = $_SESSION['models'][$model['parent']]['mtz_file'];
    }
    if ($opts['chartRama']) {
        $tasks['rama'] = "Do Ramachandran analysis and make plots (<code>ramalyze</code>)";
    }
    if ($opts['chartRota']) {
        $tasks['rota'] = "Do rotamer analysis (<code>rotalyze</code>)";
    }
    if ($opts['chartCBdev']) {
        $tasks['cbeta'] = "Do C&beta; deviation analysis and make kins (<code>cbetadev</code>)";
    }
    if ($opts['chartOmega']) {
        $tasks['omega'] = "Do cis-peptide analysis (<code>omegalyze</code>)";
    }
    if ($opts['chartCablamLow']) {
        $tasks['cablam'] = "Do CaBLAM analysis (<code>cablam_validate</code>)";
    }
    if ($opts['chartBaseP']) {
        $tasks['base-phos'] = "Do RNA sugar pucker analysis";
    }
    if ($opts['chartSuite']) {
        $tasks['suitename'] = "Do RNA backbone conformations analysis";
    }
    if ($model['stats']['use_cdl']) {
        $geomsg = "Using CDL";
    } else {
        $geomsg = "";
    }
    if ($opts['chartGeom']) {
        $tasks['geomValidation'] = "Do bond length and angle geometry analysis (<code>mp_geo</code>) {$geomsg}";
    }
    if ($opts['chartClashlist']) {
        $tasks['clashlist'] = "Run <code>clashscore</code> to find bad clashes and clashscore";
    }
    if ($opts['chartImprove']) {
        $tasks['improve'] = "Suggest / report on fixes";
    }
    if ($opts['doCharts'] && !$opts['chartMulti']) {
        $tasks['chartsummary'] = "Create summary chart";
    }
    if ($opts['chartMulti']) {
        $tasks['multichart'] = "Create multi-criterion chart";
    }
    if ($opts['chartHoriz']) {
        $tasks['runRSCC'] = "Run real-space correlation";
        $tasks['charthoriz'] = "Create horizontal RSCC chart";
    }
    if ($opts['chartCoot']) {
        $tasks['cootchart'] = "Create chart for use in Coot";
    }
    if ($opts['doKinemage']) {
        $tasks['multikin'] = "Create multi-criterion kinemage";
    }
    //if($opts['doLowRes'])       $tasks['lowResKin'] = "Create low-resolution multi-criterion kinemage";
    //$doRem40 = $opts['chartClashlist'] || $opts['chartRama'] || $opts['chartRota'];
    //if($doRem40)                $tasks['remark40'] = "Create REMARK  40 record for the PDB file";
    //}}} Set up file/directory vars and the task list
    //{{{ Run geometry programs and offer kins to user
    //{{{ Ramachandran
    if ($opts['chartRama']) {
        $startTime = time();
        setProgress($tasks, 'rama');
        // updates the progress display if running as a background job
        $outfile = "{$rawDir}/{$model['prefix']}rama.data";
        runRamachandran($infile, $outfile);
        $rama = loadRamachandran($outfile);
        makeRamachandranKin($infile, "{$kinDir}/{$model['prefix']}rama.kin");
        $tasks['rama'] .= " - preview <a href='viewking.php?{$_SESSION['sessTag']}&url={$kinURL}/{$model['prefix']}rama.kin' target='_blank'>kinemage</a>";
        setProgress($tasks, 'rama');
        // so the preview link is visible
        makeRamachandranPDF($infile, "{$chartDir}/{$model['prefix']}rama.pdf");
        $tasks['rama'] .= " | <a href='{$chartURL}/{$model['prefix']}rama.pdf' target='_blank'>PDF</a>\n";
        setProgress($tasks, 'rama');
        // so the preview link is visible
        echo "Ramachandran ran for " . (time() - $startTime) . " seconds\n";
    }
    //}}}
    //{{{ Rotamers
    if ($opts['chartRota']) {
        $startTime = time();
        setProgress($tasks, 'rota');
        // updates the progress display if running as a background job
        $outfile = "{$rawDir}/{$model['prefix']}rota.data";
        runRotamer($infile, $outfile);
        $rota = loadRotamer($outfile);
        echo "Rotamers ran for " . (time() - $startTime) . " seconds\n";
    }
    //}}}
    //{{{ C-beta deviations
    if ($opts['chartCBdev']) {
        $startTime = time();
        setProgress($tasks, 'cbeta');
        // updates the progress display if running as a background job
        $outfile = "{$rawDir}/{$model['prefix']}cbdev.data";
        runCbetaDev($infile, $outfile);
        $cbdev = loadCbetaDev($outfile);
        makeCbetaDevPlot($infile, "{$kinDir}/{$model['prefix']}cbetadev.kin");
        $tasks['cbeta'] .= " - <a href='viewking.php?{$_SESSION['sessTag']}&url={$kinURL}/{$model['prefix']}cbetadev.kin' target='_blank'>preview</a>";
        setProgress($tasks, 'cbeta');
        // so the preview link is visible
        echo "C-beta ran for " . (time() - $startTime) . " seconds\n";
    }
    //}}}
    //{{{ Omega peptides
    if ($opts['chartOmega']) {
        $startTime = time();
        setProgress($tasks, 'omega');
        $outfile = "{$rawDir}/{$model['prefix']}omega.data";
        //$outfile = "$rawDir/$model[prefix]omega-clashlist.txt";
        runOmegalyze($infile, $outfile);
        $omega = loadOmegalyze($outfile);
        echo "Omegalyze ran for " . (time() - $startTime) . " seconds\n";
    }
    //}}}
    //{{{ CaBLAM
    if ($opts['chartCablamLow']) {
        setProgress($tasks, 'cablam');
        $outfile = "{$rawDir}/{$model['prefix']}cablam.data";
        runCablam($infile, $outfile);
        $cablam = loadCablam($outfile);
    }
    //}}}
    //{{{ Run nucleic acid geometry programs and offer kins to user
    //{{{ Base-phosphate perpendiculars
    if ($opts['chartBaseP']) {
        setProgress($tasks, 'base-phos');
        // updates the progress display if running as a background job
        $outfile = "{$rawDir}/{$model['prefix']}pperp.data";
        runBasePhosPerp($infile, $outfile);
        $pperp = loadBasePhosPerp($outfile);
    }
    //}}}
    //{{{ Suitename
    if ($opts['chartSuite']) {
        setProgress($tasks, 'suitename');
        // updates the progress display if running as a background job
        $outfile = "{$chartDir}/{$model['prefix']}suitename.txt";
        runSuitenameReport($infile, $outfile);
        $suites = loadSuitenameReport($outfile);
        $tasks['suitename'] .= " - <a href='viewtext.php?{$_SESSION['sessTag']}&file={$outfile}&mode=plain' target='_blank'>preview</a>\n";
        setProgress($tasks, 'suitename');
        // so the preview link is visible
        $outfile = "{$chartDir}/{$model['prefix']}suitestring.txt";
        runSuitenameString($infile, $outfile);
        makeSuitenameKin($infile, "{$kinDir}/{$model['prefix']}suitename.kin");
    }
    //}}}
    //}}} Run nucleic acid geometry programs and offer kins to user
    //{{{ Bonds and Angles
    if ($opts['chartGeom']) {
        setProgress($tasks, 'geomValidation');
        // updates the progress display if running as a background job
        $geomfile = "{$rawDir}/{$model['prefix']}geomvalidation.data";
        runValidationReport($infile, $geomfile, $model['stats']['use_cdl']);
        //$protfile = "$rawDir/$model[prefix]protvalidation.data";
        //runValidationReport($infile, $protfile, "protein");
        //$rnafile = "$rawDir/$model[prefix]rnavalidation.data";
        //runValidationReport($infile, $rnafile, "rna");
        //$validate_bond  = loadValidationBondReport($protfile,"protein");
        //if (is_array($validate_bond))
        $validate_bond = array_merge(loadValidationBondReport($geomfile, "protein"), loadValidationBondReport($geomfile, "rna"));
        if (count($validate_bond) == 0) {
            $validate_bond = null;
        }
        $validate_angle = array_merge(loadValidationAngleReport($geomfile, "protein"), loadValidationAngleReport($geomfile, "rna"));
        if (count($validate_angle) == 0) {
            $validate_angle = null;
        }
    }
    //}}}
    //}}} Run programs and offer kins to user
    //{{{ Run all-atom contact programs and offer kins to user
    // Clashes
    if ($opts['chartClashlist']) {
        $startTime = time();
        setProgress($tasks, 'clashlist');
        // updates the progress display if running as a background job
        $outfile = "{$chartDir}/{$model['prefix']}clashlist.txt";
        #runClashlist($infile, $outfile, $reduce_blength);
        runClashscore($infile, $outfile, $reduce_blength);
        #$clash = loadClashlist($outfile);
        $clash = loadClashscore($outfile);
        //$clashPct = runClashStats($model['stats']['resolution'], $clash['scoreAll'], $clash['scoreBlt40']);
        $tasks['clashlist'] .= " - <a href='viewtext.php?{$_SESSION['sessTag']}&file={$outfile}&mode=plain' target='_blank'>preview</a>\n";
        setProgress($tasks, 'clashlist');
        // so the preview link is visible
        echo "chartClashlist ran for " . (time() - $startTime) . " seconds\n";
    }
    //}}} Run all-atom contact programs and offer kins to user
    //{{{ Run real-space correlation
    $model['raw_rscc_name'] = "{$model['parent']}_raw.rscc";
    $model['rscc_name'] = "{$model['parent']}.rscc";
    $rscc_out = "{$xrayDir}/{$model['parent']}.rscc";
    $rscc_prequel_out = "{$xrayDir}/{$model['parent']}_prequel.rscc";
    if ($opts['chartHoriz']) {
        $startTime = time();
        setProgress($tasks, 'runRSCC');
        runRscc($infile, $mtz_file, $rscc_out, $rscc_prequel_out);
        echo "runRscc ran for " . (time() - $startTime) . " seconds\n";
        echo $mtz_file;
        echo isset($mtz_file);
    }
    //}}}
    //{{{ Report on improvements (that could be) made by MolProbity
    $improveText = "";
    if ($opts['chartImprove'] && ($clash || $rota)) {
        $startTime = time();
        setProgress($tasks, 'improve');
        // updates the progress display if running as a background job
        $altpdb = mpTempfile("tmp_altH_pdb_");
        $mainClashscore = $clash ? $clash['scoreAll'] : 0;
        $mainRotaCount = $rota ? count(findRotaOutliers($rota)) : 0;
        $improvementList = array();
        if ($model['isBuilt']) {
            $altInpath = $modelDir . '/' . $_SESSION['models'][$model['parent']]['pdb'];
            reduceNoBuild($altInpath, $altpdb, $reduce_blength);
            // Rotamers
            $outfile = mpTempfile("tmp_rotamer_");
            runRotamer($altpdb, $outfile);
            $altrota = loadRotamer($outfile);
            $altRotaCount = count(findRotaOutliers($altrota));
            if ($altRotaCount > $mainRotaCount) {
                if ($altRotaCount - $mainRotaCount > 1) {
                    $improvementList[] = "fixed " . ($altRotaCount - $mainRotaCount) . " bad rotamers";
                } else {
                    $improvementList[] = "fixed " . ($altRotaCount - $mainRotaCount) . " bad rotamer";
                }
            }
            unlink($outfile);
            // Clashes
            $outfile = mpTempfile("tmp_clashlist_");
            #runClashlist($altpdb, $outfile, $reduce_blength);
            runClashscore($altpdb, $outfile, $reduce_blength);
            #$altclash = loadClashlist($outfile);
            $altclash = loadClashscore($outfile);
            if ($altclash['scoreAll'] - $mainClashscore >= 0.005) {
                //0.005 is the smallest change that will still be reported by the sprintf("%.2f") below
                $improvementList[] = "improved your clashscore by " . sprintf("%.2f", $altclash['scoreAll'] - $mainClashscore) . " points";
            }
            unlink($outfile);
            if (count($improvementList) > 0) {
                $improveText .= "<div class='feature'>By adding H to this model and allowing Asn/Gln/His flips, you have already ";
                $improveText .= implode(" and ", $improvementList);
                $improveText .= ".  <br /><b>Make sure you download the modified PDB to take advantage of these improvements! <br />NOTE: Atom positions have changed, so refinement to idealize geometry is necessary.</b></div>\n";
            }
        } elseif ($mainClashscore > 0 || $mainRotaCount > 0) {
            if ($model['parent']) {
                $altInpath = $_SESSION['models'][$model['parent']]['pdb'];
            } else {
                $altInpath = $model['pdb'];
            }
            $altInpath = "{$modelDir}/{$altInpath}";
            reduceBuild($altInpath, $altpdb, $reduce_blength);
            if ($mainRotaCount > 0) {
                $outfile = mpTempfile("tmp_rotamer_");
                runRotamer($altpdb, $outfile);
                $altrota = loadRotamer($outfile);
                $altRotaCount = count(findRotaOutliers($altrota));
                if ($altRotaCount < $mainRotaCount) {
                    $improvementList[] = "fix " . ($mainRotaCount - $altRotaCount) . " bad rotamers";
                }
                unlink($outfile);
            }
            if ($mainClashscore > 0) {
                $outfile = mpTempfile("tmp_clashlist_");
                #runClashlist($altpdb, $outfile, $reduce_blength);
                runClashscore($altpdb, $outfile, $reduce_blength);
                #$altclash = loadClashlist($outfile);
                $altclash = loadClashscore($outfile);
                if ($mainClashscore - $altclash['scoreAll'] >= 0.005) {
                    //0.005 is the smallest change that will still be reported by the sprintf("%.2f") below
                    $improvementList[] = "improve your clashscore by " . sprintf("%.2f", $mainClashscore - $altclash['scoreAll']) . " points";
                }
                unlink($outfile);
            }
            if (count($improvementList) > 0) {
                $improveText .= "<div class='feature'>By adding H to this model and allowing Asn/Gln/His flips, we could <i>automatically</i> ";
                $improveText .= implode(" and ", $improvementList);
                $improveText .= ".</div>\n";
            }
        }
        unlink($altpdb);
        echo "chart Improve ran for " . (time() - $startTime) . " seconds\n";
    }
    //}}} Report on improvements (that could be) made by by MolProbity
    //{{{ Build multi-criterion chart, kinemage, horizontal, chart
    if ($opts['doCharts']) {
        $startTime = time();
        if ($opts['chartMulti']) {
            setProgress($tasks, 'multichart');
            // updates the progress display if running as a background job
        } else {
            setProgress($tasks, 'chartsummary');
        }
        $outfile = "{$rawDir}/{$model['prefix']}multi.table";
        $snapfile = "{$chartDir}/{$model['prefix']}multi.html";
        $resout = "{$rawDir}/{$model['prefix']}multi_res.table";
        writeMulticritChart($infile, $outfile, $snapfile, $resout, $clash, $rama, $rota, $cbdev, $pperp, $suites, $validate_bond, $validate_angle, $cablam, $omega, !$opts['chartNotJustOut'], $opts['chartMulti'], $opts['chartAltloc']);
        if ($opts['chartMulti']) {
            $tasks['multichart'] .= " - <a href='viewtable.php?{$_SESSION['sessTag']}&file={$outfile}' target='_blank'>preview</a>\n";
            setProgress($tasks, 'multichart');
            // so the preview link is visible
        } else {
            $tasks['chartsummary'] .= " - <a href='viewtable.php?{$_SESSION['sessTag']}&file={$outfile}' target='_blank'>preview</a>\n";
            setProgress($tasks, 'chartsummary');
            // so the preview link is visible
        }
        if ($opts['chartHoriz']) {
            setProgress($tasks, 'charthoriz');
            $horiz_table_file = "{$rawDir}/{$model['prefix']}horiz.table";
            writeHorizontalChart($resout, $rscc_out, $outfile, $horiz_table_file, $rscc_prequel_out);
        }
        if ($opts['chartCoot']) {
            setProgress($tasks, 'cootchart');
            $outfile = "{$chartDir}/{$model['prefix']}multi-coot.scm";
            $outfile_py = "{$chartDir}/{$model['prefix']}multi-coot.py";
            #makeCootMulticritChart($infile, $outfile, $clash, $rama, $rota, $cbdev, $pperp);
            makeCootClusteredChart($infile, $outfile, $outfile_py, $clash, $rama, $rota, $cbdev, $pperp);
        }
        echo "do Charts ran for " . (time() - $startTime) . " seconds\n";
    }
    if ($opts['doKinemage']) {
        $startTime = time();
        setProgress($tasks, 'multikin');
        // updates the progress display if running as a background job
        $mcKinOpts = array('ribbons' => $opts['kinRibbons'], 'Bscale' => $opts['kinBfactor'], 'Qscale' => $opts['kinOccupancy'], 'altconf' => $opts['kinAltConfs'], 'rama' => $opts['kinRama'], 'rota' => $opts['kinRota'], 'geom' => $opts['kinGeom'], 'cbdev' => $opts['kinCBdev'], 'omega' => $opts['kinOmega'], 'cablam' => $opts['kinCablamLow'], 'pperp' => $opts['kinBaseP'], 'clashdots' => $opts['kinClashes'], 'hbdots' => $opts['kinHbonds'], 'vdwdots' => $opts['kinContacts']);
        $outfile = "{$kinDir}/{$model['prefix']}multi.kin";
        $viewRes = array();
        //echo "kinForceViews = ".$opts['kinForceViews']."\n";
        if ($opts['kinForceViews']) {
            //echo "Ran calcLocalBadness\n";
            $viewRes = array_keys(calcLocalBadness($infile, 10, $clash, $rama, $rota, $cbdev, $pperp));
        }
        makeMulticritKin2(array($infile), $outfile, $mcKinOpts, $viewRes);
        // EXPERIMENTAL: gzip compress large multikins
        if (filesize($outfile) > MP_KIN_GZIP_THRESHOLD) {
            destructiveGZipFile($outfile);
        }
        echo "do Kinemage ran for " . (time() - $startTime) . " seconds\n";
    }
    //}}} Build multi-criterion chart, kinemage
    //{{{ Low-resolution-specific analyses
    //Low-res kinemage is being simplified and merged into main kinemage
    //if($opts['doLowRes'])
    //{
    //  if($opts['kinCablamLow'] || $opts['other'])
    //  {
    //      $startTime = time();
    //      setProgress($tasks, 'lowResKin');
    //      $lowResKinOpts = array(//first column is opts, second column sets true-false
    //          'ribbons'    =>  $opts['kinRibbons'],//pass pdb w/HELIX+SHEET for this
    //          'rama'       =>  $opts['kinRama'],
    //          'geom'       =>  $opts['kinGeom'],
    //          'cbdev'      =>  $opts['kinCBdev'],
    //          'omega'      =>  $opts['kinOmega'],
    //          'cablam'     =>  $opts['kinCablamLow'],
    //          'clashdots'  =>  $opts['kinClashes']
    //      );
    //      $outfile = "$kinDir/$model[prefix]low_multi.kin";
    //      $cablamSecStrucFile = "$modelDir/$model[prefix]cablam_sec_struc_records.pdb";
    //      //$viewRes = array(); //Used with opts[kinForceViews], not necessary argument for makeMulticritKin2
    //      makeMulticritKinLowRes(array($infile), $outfile, $cablamSecStrucFile, $lowResKinOpts);
    //      if(filesize($outfile) > MP_KIN_GZIP_THRESHOLD)  destructiveGZipFile($outfile);
    //      echo "do low-res Kinemage ran for ".(time() - $startTime)." seconds\n";
    //  }
    //}
    //}}}
    //{{{ Create REMARK  40 and insert into PDB file
    //if(is_array($clash) || is_array($rama) || is_array($rota))
    //{
    //    setProgress($tasks, 'remark40'); // updates the progress display if running as a background job
    //    $remark40 = makeRemark40($clash, $rama, $rota);
    //    replacePdbRemark($infile, $remark40,  40);
    //}
    //}}} Create REMARK  40 and insert into PDB file
    //{{{ Create lab notebook entry
    $entry = "";
    if (is_array($clash) || is_array($rama) || is_array($rota) || is_array($cbdev) || is_array($pperp) || is_array($suites)) {
        $entry .= "<h3>Summary statistics</h3>\n";
        $entry .= makeSummaryStatsTable($model['stats']['resolution'], $clash, $rama, $rota, $cbdev, $pperp, $suites, $validate_bond, $validate_angle, $cablam, $omega);
    }
    $entry .= $improveText;
    if ($opts['doKinemage'] || $opts['doCharts']) {
        $entry .= "<h3>Multi-criterion visualizations</h3>\n";
        $entry .= "<div class='indent'>\n";
        $entry .= "<table width='100%' border='0'><tr valign='top'>\n";
        if ($opts['doKinemage']) {
            $entry .= "<td>" . linkAnyFile("{$model['prefix']}multi.kin", "Kinemage", "img/multikin.jpg") . "</td>\n";
        }
        if ($opts['doCharts']) {
            $entry .= "<td>" . linkAnyFile("{$model['prefix']}multi.table", "Chart", "img/multichart.jpg") . "</td>\n";
            if ($opts['chartCoot']) {
                $entry .= "<td>" . linkAnyFile("{$model['prefix']}multi-coot.scm", "To-do list for Coot", "img/multichart-coot.jpg") . "<br><small><i>Open this in Coot 0.1.2 or later using Calculate | Run Script...</i></small></td>\n";
                #$entry .= "<td>".linkAnyFile("$model[prefix]multi-coot.py", "To-do list for Coot Python", "img/multichart-coot.jpg")."<br><small><i>Open this in Coot 0.1.2 or later using Calculate | Run Script...</i></small></td>\n";
            }
            if ($opts['chartHoriz']) {
                $entry .= "<td>" . linkAnyFile("{$model['prefix']}horiz.table", "Horizontal Chart", "img/multichart_horiz.jpg") . "</td>\n";
            }
        }
        //if($opts['doLowRes']) {
        //    if($opts['kinCablamLow'] || $opts['other']) {
        //        $entry .= "<td>".linkAnyFile("$model[prefix]low_multi.kin", "LowRes MultiKin", "img/low_multikin.jpg")."</td>\n";
        //    }
        //}
        $entry .= "</tr></table>\n";
        $entry .= "</div>\n";
    }
    if ($opts['chartClashlist'] || $opts['chartRama'] || $opts['chartCBdev'] || $opts['chartSuite']) {
        $entry .= "<h3>Single-criterion visualizations</h3>";
        $entry .= "<ul>\n";
        if ($opts['chartClashlist']) {
            $entry .= "<li>" . linkAnyFile("{$model['prefix']}clashlist.txt", "Clash list") . "</li>\n";
        }
        if ($opts['chartRama']) {
            $entry .= "<li>" . linkAnyFile("{$model['prefix']}rama.kin", "Ramachandran plot kinemage") . "</li>\n";
            $entry .= "<li>" . linkAnyFile("{$model['prefix']}rama.pdf", "Ramachandran plot PDF") . "</li>\n";
        }
        if ($opts['chartCBdev']) {
            $entry .= "<li>" . linkAnyFile("{$model['prefix']}cbetadev.kin", "C&beta; deviation scatter plot") . "</li>\n";
        }
        if ($opts['chartSuite']) {
            $entry .= "<li>" . linkAnyFile("{$model['prefix']}suitename.txt", "RNA backbone report") . "</li>\n";
            $entry .= "<li>" . linkAnyFile("{$model['prefix']}suitestring.txt", "RNA backbone conformation \"sequence\"") . "</li>\n";
            $entry .= "<li>" . linkAnyFile("{$model['prefix']}suitename.kin", "RNA backbone multi-D plot of conformations") . "</li>\n";
        }
        $entry .= "</ul>\n";
    }
    if ($remark40) {
        $entry .= "<h3>REMARK  40</h3>";
        $url = "{$modelURL}/{$model['pdb']}";
        $entry .= "You can <a href='{$url}'>download your PDB file with REMARK  40</a> inserted, or the same <a href='download_trimmed.php?{$_SESSION['sessTag']}&file={$infile}'> without hydrogens</a>.\n";
        $entry .= "<p><pre>{$remark40}</pre></p>";
    }
    //}}} Create lab notebook entry
    setProgress($tasks, null);
    // everything is finished
    return $entry;
}