2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
45 #include "gromacs/commandline/pargs.h"
46 #include "gromacs/commandline/viewit.h"
47 #include "gromacs/correlationfunctions/autocorr.h"
48 #include "gromacs/fileio/enxio.h"
49 #include "gromacs/fileio/gmxfio.h"
50 #include "gromacs/fileio/tpxio.h"
51 #include "gromacs/fileio/trxio.h"
52 #include "gromacs/fileio/xvgr.h"
53 #include "gromacs/gmxana/gmx_ana.h"
54 #include "gromacs/gmxana/gstat.h"
55 #include "gromacs/math/functions.h"
56 #include "gromacs/math/units.h"
57 #include "gromacs/math/vec.h"
58 #include "gromacs/mdlib/mdebin.h"
59 #include "gromacs/mdtypes/inputrec.h"
60 #include "gromacs/mdtypes/md_enums.h"
61 #include "gromacs/topology/ifunc.h"
62 #include "gromacs/topology/mtop_lookup.h"
63 #include "gromacs/topology/mtop_util.h"
64 #include "gromacs/topology/topology.h"
65 #include "gromacs/utility/arraysize.h"
66 #include "gromacs/utility/cstringutil.h"
67 #include "gromacs/utility/fatalerror.h"
68 #include "gromacs/utility/gmxassert.h"
69 #include "gromacs/utility/pleasecite.h"
70 #include "gromacs/utility/smalloc.h"
71 #include "gromacs/utility/strconvert.h"
73 static real minthird = -1.0/3.0, minsixth = -1.0/6.0;
75 static double mypow(double x, double y)
79 return std::pow(x, y);
87 static real blk_value(t_enxblock *blk, int sub, int index)
89 range_check(index, 0, blk->sub[sub].nr);
90 if (blk->sub[sub].type == xdr_datatype_float)
92 return blk->sub[sub].fval[index];
94 else if (blk->sub[sub].type == xdr_datatype_double)
96 return blk->sub[sub].dval[index];
100 gmx_incons("Unknown datatype in t_enxblock");
104 static int *select_it(int nre, char *nm[], int *nset)
109 gmx_bool bVerbose = TRUE;
111 if ((getenv("GMX_ENER_VERBOSE")) != nullptr)
116 fprintf(stderr, "Select the terms you want from the following list\n");
117 fprintf(stderr, "End your selection with 0\n");
121 for (k = 0; (k < nre); )
123 for (j = 0; (j < 4) && (k < nre); j++, k++)
125 fprintf(stderr, " %3d=%14s", k+1, nm[k]);
127 fprintf(stderr, "\n");
134 if (1 != scanf("%d", &n))
136 gmx_fatal(FARGS, "Error reading user input");
138 if ((n > 0) && (n <= nre))
146 for (i = (*nset) = 0; (i < nre); i++)
159 static void get_orires_parms(const char *topnm, t_inputrec *ir,
160 int *nor, int *nex, int **label, real **obs)
170 read_tpx(topnm, ir, box, &natoms, nullptr, nullptr, &mtop);
171 top = gmx_mtop_t_to_t_topology(&mtop, FALSE);
173 ip = top.idef.iparams;
174 iatom = top.idef.il[F_ORIRES].iatoms;
176 /* Count how many distance restraint there are... */
177 nb = top.idef.il[F_ORIRES].nr;
180 gmx_fatal(FARGS, "No orientation restraints in topology!\n");
187 for (i = 0; i < nb; i += 3)
189 (*label)[i/3] = ip[iatom[i]].orires.label;
190 (*obs)[i/3] = ip[iatom[i]].orires.obs;
191 if (ip[iatom[i]].orires.ex >= *nex)
193 *nex = ip[iatom[i]].orires.ex+1;
196 fprintf(stderr, "Found %d orientation restraints with %d experiments",
198 done_top_mtop(&top, &mtop);
201 static int get_bounds(const char *topnm,
202 real **bounds, int **index, int **dr_pair, int *npairs,
203 gmx_mtop_t *mtop, gmx_localtop_t **ltop, t_inputrec *ir)
206 t_functype *functype;
208 int natoms, i, j, k, type, ftype, natom;
216 read_tpx(topnm, ir, box, &natoms, nullptr, nullptr, mtop);
218 top = gmx_mtop_generate_local_top(mtop, ir->efep != efepNO);
221 functype = top->idef.functype;
222 ip = top->idef.iparams;
224 /* Count how many distance restraint there are... */
225 nb = top->idef.il[F_DISRES].nr;
228 gmx_fatal(FARGS, "No distance restraints in topology!\n");
231 /* Allocate memory */
236 /* Fill the bound array */
238 for (i = 0; (i < top->idef.ntypes); i++)
241 if (ftype == F_DISRES)
244 label1 = ip[i].disres.label;
245 b[nb] = ip[i].disres.up1;
252 /* Fill the index array */
254 disres = &(top->idef.il[F_DISRES]);
255 iatom = disres->iatoms;
256 for (i = j = k = 0; (i < disres->nr); )
259 ftype = top->idef.functype[type];
260 natom = interaction_function[ftype].nratoms+1;
261 if (label1 != top->idef.iparams[type].disres.label)
264 label1 = top->idef.iparams[type].disres.label;
274 gmx_incons("get_bounds for distance restraints");
283 static void calc_violations(real rt[], real rav3[], int nb, const int index[],
284 real bounds[], real *viol, double *st, double *sa)
286 const real sixth = 1.0/6.0;
288 double rsum, rav, sumaver, sumt;
292 for (i = 0; (i < nb); i++)
296 for (j = index[i]; (j < index[i+1]); j++)
300 viol[j] += mypow(rt[j], -3.0);
302 rav += gmx::square(rav3[j]);
303 rsum += mypow(rt[j], -6);
305 rsum = std::max(0.0, mypow(rsum, -sixth)-bounds[i]);
306 rav = std::max(0.0, mypow(rav, -sixth)-bounds[i]);
315 static void analyse_disre(const char *voutfn, int nframes,
316 real violaver[], real bounds[], int index[],
317 int pair[], int nbounds,
318 const gmx_output_env_t *oenv)
321 double sum, sumt, sumaver;
324 /* Subtract bounds from distances, to calculate violations */
325 calc_violations(violaver, violaver,
326 nbounds, pair, bounds, nullptr, &sumt, &sumaver);
329 fprintf(stdout, "\nSum of violations averaged over simulation: %g nm\n",
331 fprintf(stdout, "Largest violation averaged over simulation: %g nm\n\n",
334 vout = xvgropen(voutfn, "r\\S-3\\N average violations", "DR Index", "nm",
338 for (i = 0; (i < nbounds); i++)
340 /* Do ensemble averaging */
342 for (j = pair[i]; (j < pair[i+1]); j++)
344 sumaver += gmx::square(violaver[j]/nframes);
346 sumaver = std::max(0.0, mypow(sumaver, minsixth)-bounds[i]);
349 sum = std::max(sum, sumaver);
350 fprintf(vout, "%10d %10.5e\n", index[i], sumaver);
353 for (j = 0; (j < dr.ndr); j++)
355 fprintf(vout, "%10d %10.5e\n", j, mypow(violaver[j]/nframes, minthird));
360 fprintf(stdout, "\nSum of violations averaged over simulation: %g nm\n",
362 fprintf(stdout, "Largest violation averaged over simulation: %g nm\n\n", sum);
364 do_view(oenv, voutfn, "-graphtype bar");
367 static void print_time(FILE *fp, double t)
369 fprintf(fp, "%12.6f", t);
372 int gmx_nmr(int argc, char *argv[])
374 const char *desc[] = {
375 "[THISMODULE] extracts distance or orientation restraint",
376 "data from an energy file. The user is prompted to interactively",
377 "select the desired terms.[PAR]",
379 "When the [TT]-viol[tt] option is set, the time averaged",
380 "violations are plotted and the running time-averaged and",
381 "instantaneous sum of violations are recalculated. Additionally",
382 "running time-averaged and instantaneous distances between",
383 "selected pairs can be plotted with the [TT]-pairs[tt] option.[PAR]",
385 "Options [TT]-ora[tt], [TT]-ort[tt], [TT]-oda[tt], [TT]-odr[tt] and",
386 "[TT]-odt[tt] are used for analyzing orientation restraint data.",
387 "The first two options plot the orientation, the last three the",
388 "deviations of the orientations from the experimental values.",
389 "The options that end on an 'a' plot the average over time",
390 "as a function of restraint. The options that end on a 't'",
391 "prompt the user for restraint label numbers and plot the data",
392 "as a function of time. Option [TT]-odr[tt] plots the RMS",
393 "deviation as a function of restraint.",
394 "When the run used time or ensemble averaged orientation restraints,",
395 "option [TT]-orinst[tt] can be used to analyse the instantaneous,",
396 "not ensemble-averaged orientations and deviations instead of",
397 "the time and ensemble averages.[PAR]",
399 "Option [TT]-oten[tt] plots the eigenvalues of the molecular order",
400 "tensor for each orientation restraint experiment. With option",
401 "[TT]-ovec[tt] also the eigenvectors are plotted.[PAR]",
405 static gmx_bool bPrAll = FALSE;
406 static gmx_bool bDp = FALSE, bOrinst = FALSE, bOvec = FALSE;
409 { "-dp", FALSE, etBOOL, {&bDp},
410 "Print energies in high precision" },
411 { "-skip", FALSE, etINT, {&skip},
412 "Skip number of frames between data points" },
413 { "-aver", FALSE, etBOOL, {&bPrAll},
414 "Also print the exact average and rmsd stored in the energy frames (only when 1 term is requested)" },
415 { "-orinst", FALSE, etBOOL, {&bOrinst},
416 "Analyse instantaneous orientation data" },
417 { "-ovec", FALSE, etBOOL, {&bOvec},
418 "Also plot the eigenvectors with [TT]-oten[tt]" }
420 const char * drleg[] = {
425 FILE /* *out = NULL,*/ *out_disre = nullptr, *fp_pairs = nullptr, *fort = nullptr, *fodt = nullptr, *foten = nullptr;
429 gmx_localtop_t *top = nullptr;
430 gmx_enxnm_t *enm = nullptr;
432 int nre, teller, teller_disre;
433 int nor = 0, nex = 0, norfr = 0, enx_i = 0;
434 real *bounds = nullptr, *violaver = nullptr, *oobs = nullptr, *orient = nullptr, *odrms = nullptr;
435 int *index = nullptr, *pair = nullptr, norsel = 0, *orsel = nullptr, *or_label = nullptr;
436 int nbounds = 0, npairs;
437 gmx_bool bDisRe, bDRAll, bORA, bORT, bODA, bODR, bODT, bORIRE, bOTEN;
439 double sumaver, sumt;
440 int *set = nullptr, i, j, k, nset, sss;
441 char **pairleg, **odtleg, **otenleg;
442 char **leg = nullptr;
443 const char *anm_j, *anm_k, *resnm_j, *resnm_k;
444 int resnr_j, resnr_k;
445 const char *orinst_sub = "@ subtitle \"instantaneous\"\n";
447 gmx_output_env_t *oenv;
448 t_enxblock *blk_disre = nullptr;
452 { efEDR, "-f", nullptr, ffREAD },
453 { efEDR, "-f2", nullptr, ffOPTRD },
454 { efTPR, "-s", nullptr, ffOPTRD },
455 // { efXVG, "-o", "energy", ffWRITE },
456 { efXVG, "-viol", "violaver", ffOPTWR },
457 { efXVG, "-pairs", "pairs", ffOPTWR },
458 { efXVG, "-ora", "orienta", ffOPTWR },
459 { efXVG, "-ort", "orientt", ffOPTWR },
460 { efXVG, "-oda", "orideva", ffOPTWR },
461 { efXVG, "-odr", "oridevr", ffOPTWR },
462 { efXVG, "-odt", "oridevt", ffOPTWR },
463 { efXVG, "-oten", "oriten", ffOPTWR }
465 #define NFILE asize(fnm)
469 if (!parse_common_args(&argc, argv,
470 PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END,
471 NFILE, fnm, npargs, pa, asize(desc), desc, 0, nullptr, &oenv))
476 bDRAll = opt2bSet("-pairs", NFILE, fnm);
477 bDisRe = opt2bSet("-viol", NFILE, fnm) || bDRAll;
478 bORA = opt2bSet("-ora", NFILE, fnm);
479 bORT = opt2bSet("-ort", NFILE, fnm);
480 bODA = opt2bSet("-oda", NFILE, fnm);
481 bODR = opt2bSet("-odr", NFILE, fnm);
482 bODT = opt2bSet("-odt", NFILE, fnm);
483 bORIRE = bORA || bORT || bODA || bODR || bODT;
484 bOTEN = opt2bSet("-oten", NFILE, fnm);
485 if (!(bDRAll || bDisRe || bORA || bORT || bODA || bODR || bODT || bORIRE || bOTEN))
487 printf("No output selected. Run with -h to see options. Terminating program.\n");
492 fp = open_enx(ftp2fn(efEDR, NFILE, fnm), "r");
493 do_enxnms(fp, &nre, &enm);
494 free_enxnms(nre, enm);
496 t_inputrec irInstance;
497 t_inputrec *ir = &irInstance;
504 get_orires_parms(ftp2fn(efTPR, NFILE, fnm), ir,
505 &nor, &nex, &or_label, &oobs);
529 fprintf(stderr, "Select the orientation restraint labels you want (-1 is all)\n");
530 fprintf(stderr, "End your selection with 0\n");
537 if (1 != scanf("%d", &(orsel[j])))
539 gmx_fatal(FARGS, "Error reading user input");
542 while (orsel[j] > 0);
545 fprintf(stderr, "Selecting all %d orientation restraints\n", nor);
548 for (i = 0; i < nor; i++)
555 /* Build the selection */
557 for (i = 0; i < j; i++)
559 for (k = 0; k < nor; k++)
561 if (or_label[k] == orsel[i])
570 fprintf(stderr, "Orientation restraint label %d not found\n",
575 snew(odtleg, norsel);
576 for (i = 0; i < norsel; i++)
578 snew(odtleg[i], 256);
579 sprintf(odtleg[i], "%d", or_label[orsel[i]]);
583 fort = xvgropen(opt2fn("-ort", NFILE, fnm), "Calculated orientations",
584 "Time (ps)", "", oenv);
585 if (bOrinst && output_env_get_print_xvgr_codes(oenv))
587 fprintf(fort, "%s", orinst_sub);
589 xvgr_legend(fort, norsel, odtleg, oenv);
593 fodt = xvgropen(opt2fn("-odt", NFILE, fnm),
594 "Orientation restraint deviation",
595 "Time (ps)", "", oenv);
596 if (bOrinst && output_env_get_print_xvgr_codes(oenv))
598 fprintf(fodt, "%s", orinst_sub);
600 xvgr_legend(fodt, norsel, odtleg, oenv);
602 for (i = 0; i < norsel; i++)
611 foten = xvgropen(opt2fn("-oten", NFILE, fnm),
612 "Order tensor", "Time (ps)", "", oenv);
613 snew(otenleg, bOvec ? nex*12 : nex*3);
614 for (i = 0; i < nex; i++)
616 for (j = 0; j < 3; j++)
618 sprintf(buf, "eig%d", j+1);
619 otenleg[(bOvec ? 12 : 3)*i+j] = gmx_strdup(buf);
623 for (j = 0; j < 9; j++)
625 sprintf(buf, "vec%d%s", j/3+1, j%3 == 0 ? "x" : (j%3 == 1 ? "y" : "z"));
626 otenleg[12*i+3+j] = gmx_strdup(buf);
630 xvgr_legend(foten, bOvec ? nex*12 : nex*3, otenleg, oenv);
631 for (j = 0; j < 3; j++)
640 nbounds = get_bounds(ftp2fn(efTPR, NFILE, fnm), &bounds, &index, &pair, &npairs,
642 snew(violaver, npairs);
643 out_disre = xvgropen(opt2fn("-o", NFILE, fnm), "Sum of Violations",
644 "Time (ps)", "nm", oenv);
645 xvgr_legend(out_disre, 2, drleg, oenv);
648 fp_pairs = xvgropen(opt2fn("-pairs", NFILE, fnm), "Pair Distances",
649 "Time (ps)", "Distance (nm)", oenv);
650 if (output_env_get_print_xvgr_codes(oenv))
652 fprintf(fp_pairs, "@ subtitle \"averaged (tau=%g) and instantaneous\"\n",
658 /* Initiate counters */
663 /* This loop searches for the first frame (when -b option is given),
664 * or when this has been found it reads just one energy frame
668 bCont = do_enx(fp, &fr);
671 timecheck = check_times(fr.t);
674 while (bCont && (timecheck < 0));
676 if ((timecheck == 0) && bCont)
679 * Define distance restraint legends. Can only be done after
680 * the first frame has been read... (Then we know how many there are)
682 blk_disre = find_block_id_enxframe(&fr, enxDISRE, nullptr);
683 if (bDisRe && bDRAll && !leg && blk_disre)
688 fa = top->idef.il[F_DISRES].iatoms;
689 ip = top->idef.iparams;
690 if (blk_disre->nsub != 2 ||
691 (blk_disre->sub[0].nr != blk_disre->sub[1].nr) )
693 gmx_incons("Number of disre sub-blocks not equal to 2");
696 ndisre = blk_disre->sub[0].nr;
697 if (ndisre != top->idef.il[F_DISRES].nr/3)
699 gmx_fatal(FARGS, "Number of disre pairs in the energy file (%d) does not match the number in the run input file (%d)\n",
700 ndisre, top->idef.il[F_DISRES].nr/3);
702 snew(pairleg, ndisre);
704 for (i = 0; i < ndisre; i++)
706 snew(pairleg[i], 30);
709 mtopGetAtomAndResidueName(&mtop, j, &molb, &anm_j, &resnr_j, &resnm_j, nullptr);
710 mtopGetAtomAndResidueName(&mtop, k, &molb, &anm_k, &resnr_k, &resnm_k, nullptr);
711 sprintf(pairleg[i], "%d %s %d %s (%d)",
712 resnr_j, anm_j, resnr_k, anm_k,
713 ip[fa[3*i]].disres.label);
715 set = select_it(ndisre, pairleg, &nset);
717 for (i = 0; (i < nset); i++)
720 sprintf(leg[2*i], "a %s", pairleg[set[i]]);
721 snew(leg[2*i+1], 32);
722 sprintf(leg[2*i+1], "i %s", pairleg[set[i]]);
724 xvgr_legend(fp_pairs, 2*nset, leg, oenv);
728 * Printing time, only when we do not want to skip frames
730 if (!skip || teller % skip == 0)
734 /*******************************************
735 * D I S T A N C E R E S T R A I N T S
736 *******************************************/
739 GMX_RELEASE_ASSERT(blk_disre != nullptr, "Trying to dereference NULL blk_disre pointer");
741 float *disre_rt = blk_disre->sub[0].fval;
742 float *disre_rm3tav = blk_disre->sub[1].fval;
744 double *disre_rt = blk_disre->sub[0].dval;
745 double *disre_rm3tav = blk_disre->sub[1].dval;
748 print_time(out_disre, fr.t);
749 if (violaver == nullptr)
751 snew(violaver, ndisre);
754 /* Subtract bounds from distances, to calculate violations */
755 calc_violations(disre_rt, disre_rm3tav,
756 nbounds, pair, bounds, violaver, &sumt, &sumaver);
758 fprintf(out_disre, " %8.4f %8.4f\n", sumaver, sumt);
761 print_time(fp_pairs, fr.t);
762 for (i = 0; (i < nset); i++)
765 fprintf(fp_pairs, " %8.4f", mypow(disre_rm3tav[sss], minthird));
766 fprintf(fp_pairs, " %8.4f", disre_rt[sss]);
768 fprintf(fp_pairs, "\n");
774 /*******************************************
776 *******************************************/
779 t_enxblock *blk = find_block_id_enxframe(&fr, enx_i, nullptr);
784 gmx_fatal(FARGS, "Orientational restraints read in incorrectly.");
787 if (blk->sub[0].nr != nor)
789 gmx_fatal(FARGS, "Number of orientation restraints in energy file (%d) does not match with the topology (%d)", blk->sub[0].nr);
793 for (i = 0; i < nor; i++)
795 orient[i] += blk_value(blk, 0, i);
800 for (i = 0; i < nor; i++)
802 real v = blk_value(blk, 0, i);
803 odrms[i] += gmx::square(v - oobs[i]);
808 fprintf(fort, " %10f", fr.t);
809 for (i = 0; i < norsel; i++)
811 fprintf(fort, " %g", blk_value(blk, 0, orsel[i]));
817 fprintf(fodt, " %10f", fr.t);
818 for (i = 0; i < norsel; i++)
820 fprintf(fodt, " %g", blk_value(blk, 0, orsel[i])-oobs[orsel[i]]);
826 blk = find_block_id_enxframe(&fr, enxORT, nullptr);
831 gmx_fatal(FARGS, "Orientational restraints read in incorrectly");
834 if (blk->sub[0].nr != nex*12)
836 gmx_fatal(FARGS, "Number of orientation experiments in energy file (%d) does not match with the topology (%d)",
837 blk->sub[0].nr/12, nex);
839 fprintf(foten, " %10f", fr.t);
840 for (i = 0; i < nex; i++)
842 for (j = 0; j < (bOvec ? 12 : 3); j++)
844 fprintf(foten, " %g", blk_value(blk, 0, i*12+j));
847 fprintf(foten, "\n");
854 while (bCont && (timecheck == 0));
857 fprintf(stderr, "\n");
861 xvgrclose(out_disre);
879 FILE *out = xvgropen(opt2fn("-ora", NFILE, fnm),
880 "Average calculated orientations",
881 "Restraint label", "", oenv);
882 if (bOrinst && output_env_get_print_xvgr_codes(oenv))
884 fprintf(out, "%s", orinst_sub);
886 for (i = 0; i < nor; i++)
888 fprintf(out, "%5d %g\n", or_label[i], orient[i]/norfr);
894 FILE *out = xvgropen(opt2fn("-oda", NFILE, fnm),
895 "Average restraint deviation",
896 "Restraint label", "", oenv);
897 if (bOrinst && output_env_get_print_xvgr_codes(oenv))
899 fprintf(out, "%s", orinst_sub);
901 for (i = 0; i < nor; i++)
903 fprintf(out, "%5d %g\n", or_label[i], orient[i]/norfr-oobs[i]);
909 FILE *out = xvgropen(opt2fn("-odr", NFILE, fnm),
910 "RMS orientation restraint deviations",
911 "Restraint label", "", oenv);
912 if (bOrinst && output_env_get_print_xvgr_codes(oenv))
914 fprintf(out, "%s", orinst_sub);
916 for (i = 0; i < nor; i++)
918 fprintf(out, "%5d %g\n", or_label[i], std::sqrt(odrms[i]/norfr));
922 // Clean up orires variables.
935 analyse_disre(opt2fn("-viol", NFILE, fnm),
936 teller_disre, violaver, bounds, index, pair, nbounds, oenv);
939 const char *nxy = "-nxy";
941 do_view(oenv, opt2fn_null("-ora", NFILE, fnm), nxy);
942 do_view(oenv, opt2fn_null("-ort", NFILE, fnm), nxy);
943 do_view(oenv, opt2fn_null("-oda", NFILE, fnm), nxy);
944 do_view(oenv, opt2fn_null("-odr", NFILE, fnm), nxy);
945 do_view(oenv, opt2fn_null("-odt", NFILE, fnm), nxy);
946 do_view(oenv, opt2fn_null("-oten", NFILE, fnm), nxy);
948 output_env_done(oenv);