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,2019, 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/energyoutput.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/trajectory/energyframe.h"
66 #include "gromacs/trajectoryanalysis/topologyinformation.h"
67 #include "gromacs/utility/arraysize.h"
68 #include "gromacs/utility/cstringutil.h"
69 #include "gromacs/utility/fatalerror.h"
70 #include "gromacs/utility/gmxassert.h"
71 #include "gromacs/utility/pleasecite.h"
72 #include "gromacs/utility/smalloc.h"
73 #include "gromacs/utility/strconvert.h"
75 static real minthird = -1.0/3.0, minsixth = -1.0/6.0;
77 static double mypow(double x, double y)
81 return std::pow(x, y);
89 static real blk_value(t_enxblock *blk, int sub, int index)
91 range_check(index, 0, blk->sub[sub].nr);
92 if (blk->sub[sub].type == xdr_datatype_float)
94 return blk->sub[sub].fval[index];
96 else if (blk->sub[sub].type == xdr_datatype_double)
98 return blk->sub[sub].dval[index];
102 gmx_incons("Unknown datatype in t_enxblock");
106 static int *select_it(int nre, char *nm[], int *nset)
111 gmx_bool bVerbose = TRUE;
113 if ((getenv("GMX_ENER_VERBOSE")) != nullptr)
118 fprintf(stderr, "Select the terms you want from the following list\n");
119 fprintf(stderr, "End your selection with 0\n");
123 for (k = 0; (k < nre); )
125 for (j = 0; (j < 4) && (k < nre); j++, k++)
127 fprintf(stderr, " %3d=%14s", k+1, nm[k]);
129 fprintf(stderr, "\n");
136 if (1 != scanf("%d", &n))
138 gmx_fatal(FARGS, "Error reading user input");
140 if ((n > 0) && (n <= nre))
148 for (i = (*nset) = 0; (i < nre); i++)
161 static void get_orires_parms(const char *topnm, t_inputrec *ir,
162 int *nor, int *nex, int **label, real **obs)
172 read_tpx(topnm, ir, box, &natoms, nullptr, nullptr, &mtop);
173 top = gmx_mtop_t_to_t_topology(&mtop, FALSE);
175 ip = top.idef.iparams;
176 iatom = top.idef.il[F_ORIRES].iatoms;
178 /* Count how many distance restraint there are... */
179 nb = top.idef.il[F_ORIRES].nr;
182 gmx_fatal(FARGS, "No orientation restraints in topology!\n");
189 for (i = 0; i < nb; i += 3)
191 (*label)[i/3] = ip[iatom[i]].orires.label;
192 (*obs)[i/3] = ip[iatom[i]].orires.obs;
193 if (ip[iatom[i]].orires.ex >= *nex)
195 *nex = ip[iatom[i]].orires.ex+1;
198 fprintf(stderr, "Found %d orientation restraints with %d experiments",
200 done_top_mtop(&top, &mtop);
203 static int get_bounds(real **bounds, int **index, int **dr_pair, int *npairs,
206 t_functype *functype;
208 int i, j, k, type, ftype, natom;
215 functype = top->idef.functype;
216 ip = top->idef.iparams;
218 /* Count how many distance restraint there are... */
219 nb = top->idef.il[F_DISRES].nr;
222 gmx_fatal(FARGS, "No distance restraints in topology!\n");
225 /* Allocate memory */
230 /* Fill the bound array */
232 for (i = 0; (i < top->idef.ntypes); i++)
235 if (ftype == F_DISRES)
238 label1 = ip[i].disres.label;
239 b[nb] = ip[i].disres.up1;
246 /* Fill the index array */
248 disres = &(top->idef.il[F_DISRES]);
249 iatom = disres->iatoms;
250 for (i = j = k = 0; (i < disres->nr); )
253 ftype = top->idef.functype[type];
254 natom = interaction_function[ftype].nratoms+1;
255 if (label1 != top->idef.iparams[type].disres.label)
258 label1 = top->idef.iparams[type].disres.label;
268 gmx_incons("get_bounds for distance restraints");
277 static void calc_violations(real rt[], real rav3[], int nb, const int index[],
278 real bounds[], real *viol, double *st, double *sa)
280 const real sixth = 1.0/6.0;
282 double rsum, rav, sumaver, sumt;
286 for (i = 0; (i < nb); i++)
290 for (j = index[i]; (j < index[i+1]); j++)
294 viol[j] += mypow(rt[j], -3.0);
296 rav += gmx::square(rav3[j]);
297 rsum += mypow(rt[j], -6);
299 rsum = std::max(0.0, mypow(rsum, -sixth)-bounds[i]);
300 rav = std::max(0.0, mypow(rav, -sixth)-bounds[i]);
309 static void analyse_disre(const char *voutfn, int nframes,
310 real violaver[], real bounds[], int index[],
311 int pair[], int nbounds,
312 const gmx_output_env_t *oenv)
315 double sum, sumt, sumaver;
318 /* Subtract bounds from distances, to calculate violations */
319 calc_violations(violaver, violaver,
320 nbounds, pair, bounds, nullptr, &sumt, &sumaver);
323 fprintf(stdout, "\nSum of violations averaged over simulation: %g nm\n",
325 fprintf(stdout, "Largest violation averaged over simulation: %g nm\n\n",
328 vout = xvgropen(voutfn, "r\\S-3\\N average violations", "DR Index", "nm",
332 for (i = 0; (i < nbounds); i++)
334 /* Do ensemble averaging */
336 for (j = pair[i]; (j < pair[i+1]); j++)
338 sumaver += gmx::square(violaver[j]/real(nframes));
340 sumaver = std::max(0.0, mypow(sumaver, minsixth)-bounds[i]);
343 sum = std::max(sum, sumaver);
344 fprintf(vout, "%10d %10.5e\n", index[i], sumaver);
347 for (j = 0; (j < dr.ndr); j++)
349 fprintf(vout, "%10d %10.5e\n", j, mypow(violaver[j]/real(nframes), minthird));
354 fprintf(stdout, "\nSum of violations averaged over simulation: %g nm\n",
356 fprintf(stdout, "Largest violation averaged over simulation: %g nm\n\n", sum);
358 do_view(oenv, voutfn, "-graphtype bar");
361 static void print_time(FILE *fp, double t)
363 fprintf(fp, "%12.6f", t);
366 int gmx_nmr(int argc, char *argv[])
368 const char *desc[] = {
369 "[THISMODULE] extracts distance or orientation restraint",
370 "data from an energy file. The user is prompted to interactively",
371 "select the desired terms.[PAR]",
373 "When the [TT]-viol[tt] option is set, the time averaged",
374 "violations are plotted and the running time-averaged and",
375 "instantaneous sum of violations are recalculated. Additionally",
376 "running time-averaged and instantaneous distances between",
377 "selected pairs can be plotted with the [TT]-pairs[tt] option.[PAR]",
379 "Options [TT]-ora[tt], [TT]-ort[tt], [TT]-oda[tt], [TT]-odr[tt] and",
380 "[TT]-odt[tt] are used for analyzing orientation restraint data.",
381 "The first two options plot the orientation, the last three the",
382 "deviations of the orientations from the experimental values.",
383 "The options that end on an 'a' plot the average over time",
384 "as a function of restraint. The options that end on a 't'",
385 "prompt the user for restraint label numbers and plot the data",
386 "as a function of time. Option [TT]-odr[tt] plots the RMS",
387 "deviation as a function of restraint.",
388 "When the run used time or ensemble averaged orientation restraints,",
389 "option [TT]-orinst[tt] can be used to analyse the instantaneous,",
390 "not ensemble-averaged orientations and deviations instead of",
391 "the time and ensemble averages.[PAR]",
393 "Option [TT]-oten[tt] plots the eigenvalues of the molecular order",
394 "tensor for each orientation restraint experiment. With option",
395 "[TT]-ovec[tt] also the eigenvectors are plotted.[PAR]",
399 static gmx_bool bPrAll = FALSE;
400 static gmx_bool bDp = FALSE, bOrinst = FALSE, bOvec = FALSE;
403 { "-dp", FALSE, etBOOL, {&bDp},
404 "Print energies in high precision" },
405 { "-skip", FALSE, etINT, {&skip},
406 "Skip number of frames between data points" },
407 { "-aver", FALSE, etBOOL, {&bPrAll},
408 "Also print the exact average and rmsd stored in the energy frames (only when 1 term is requested)" },
409 { "-orinst", FALSE, etBOOL, {&bOrinst},
410 "Analyse instantaneous orientation data" },
411 { "-ovec", FALSE, etBOOL, {&bOvec},
412 "Also plot the eigenvectors with [TT]-oten[tt]" }
414 const char * drleg[] = {
419 FILE /* *out = NULL,*/ *out_disre = nullptr, *fp_pairs = nullptr, *fort = nullptr, *fodt = nullptr, *foten = nullptr;
423 gmx_enxnm_t *enm = nullptr;
425 int nre, teller, teller_disre;
426 int nor = 0, nex = 0, norfr = 0, enx_i = 0;
427 real *bounds = nullptr, *violaver = nullptr, *oobs = nullptr, *orient = nullptr, *odrms = nullptr;
428 int *index = nullptr, *pair = nullptr, norsel = 0, *orsel = nullptr, *or_label = nullptr;
429 int nbounds = 0, npairs;
430 gmx_bool bDisRe, bDRAll, bORA, bORT, bODA, bODR, bODT, bORIRE, bOTEN;
432 double sumaver, sumt;
433 int *set = nullptr, i, j, k, nset, sss;
434 char **pairleg, **odtleg, **otenleg;
435 char **leg = nullptr;
436 const char *anm_j, *anm_k, *resnm_j, *resnm_k;
437 int resnr_j, resnr_k;
438 const char *orinst_sub = "@ subtitle \"instantaneous\"\n";
440 gmx_output_env_t *oenv;
441 t_enxblock *blk_disre = nullptr;
445 { efEDR, "-f", nullptr, ffREAD },
446 { efEDR, "-f2", nullptr, ffOPTRD },
447 { efTPR, "-s", nullptr, ffOPTRD },
448 // { efXVG, "-o", "energy", ffWRITE },
449 { efXVG, "-viol", "violaver", ffOPTWR },
450 { efXVG, "-pairs", "pairs", ffOPTWR },
451 { efXVG, "-ora", "orienta", ffOPTWR },
452 { efXVG, "-ort", "orientt", ffOPTWR },
453 { efXVG, "-oda", "orideva", ffOPTWR },
454 { efXVG, "-odr", "oridevr", ffOPTWR },
455 { efXVG, "-odt", "oridevt", ffOPTWR },
456 { efXVG, "-oten", "oriten", ffOPTWR }
458 #define NFILE asize(fnm)
462 if (!parse_common_args(&argc, argv,
463 PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END,
464 NFILE, fnm, npargs, pa, asize(desc), desc, 0, nullptr, &oenv))
469 bDRAll = opt2bSet("-pairs", NFILE, fnm);
470 bDisRe = opt2bSet("-viol", NFILE, fnm) || bDRAll;
471 bORA = opt2bSet("-ora", NFILE, fnm);
472 bORT = opt2bSet("-ort", NFILE, fnm);
473 bODA = opt2bSet("-oda", NFILE, fnm);
474 bODR = opt2bSet("-odr", NFILE, fnm);
475 bODT = opt2bSet("-odt", NFILE, fnm);
476 bORIRE = bORA || bORT || bODA || bODR || bODT;
477 bOTEN = opt2bSet("-oten", NFILE, fnm);
478 if (!(bDRAll || bDisRe || bORA || bORT || bODA || bODR || bODT || bORIRE || bOTEN))
480 printf("No output selected. Run with -h to see options. Terminating program.\n");
485 fp = open_enx(ftp2fn(efEDR, NFILE, fnm), "r");
486 do_enxnms(fp, &nre, &enm);
487 free_enxnms(nre, enm);
489 t_inputrec irInstance;
490 t_inputrec *ir = &irInstance;
492 gmx::TopologyInformation topInfo;
497 get_orires_parms(ftp2fn(efTPR, NFILE, fnm), ir,
498 &nor, &nex, &or_label, &oobs);
522 fprintf(stderr, "Select the orientation restraint labels you want (-1 is all)\n");
523 fprintf(stderr, "End your selection with 0\n");
530 if (1 != scanf("%d", &(orsel[j])))
532 gmx_fatal(FARGS, "Error reading user input");
535 while (orsel[j] > 0);
538 fprintf(stderr, "Selecting all %d orientation restraints\n", nor);
541 for (i = 0; i < nor; i++)
548 /* Build the selection */
550 for (i = 0; i < j; i++)
552 for (k = 0; k < nor; k++)
554 if (or_label[k] == orsel[i])
563 fprintf(stderr, "Orientation restraint label %d not found\n",
568 snew(odtleg, norsel);
569 for (i = 0; i < norsel; i++)
571 snew(odtleg[i], 256);
572 sprintf(odtleg[i], "%d", or_label[orsel[i]]);
576 fort = xvgropen(opt2fn("-ort", NFILE, fnm), "Calculated orientations",
577 "Time (ps)", "", oenv);
578 if (bOrinst && output_env_get_print_xvgr_codes(oenv))
580 fprintf(fort, "%s", orinst_sub);
582 xvgr_legend(fort, norsel, odtleg, oenv);
586 fodt = xvgropen(opt2fn("-odt", NFILE, fnm),
587 "Orientation restraint deviation",
588 "Time (ps)", "", oenv);
589 if (bOrinst && output_env_get_print_xvgr_codes(oenv))
591 fprintf(fodt, "%s", orinst_sub);
593 xvgr_legend(fodt, norsel, odtleg, oenv);
595 for (i = 0; i < norsel; i++)
604 foten = xvgropen(opt2fn("-oten", NFILE, fnm),
605 "Order tensor", "Time (ps)", "", oenv);
606 snew(otenleg, bOvec ? nex*12 : nex*3);
607 for (i = 0; i < nex; i++)
609 for (j = 0; j < 3; j++)
611 sprintf(buf, "eig%d", j+1);
612 otenleg[(bOvec ? 12 : 3)*i+j] = gmx_strdup(buf);
616 for (j = 0; j < 9; j++)
618 sprintf(buf, "vec%d%s", j/3+1, j%3 == 0 ? "x" : (j%3 == 1 ? "y" : "z"));
619 otenleg[12*i+3+j] = gmx_strdup(buf);
623 xvgr_legend(foten, bOvec ? nex*12 : nex*3, otenleg, oenv);
624 for (j = 0; j < 3; j++)
634 topInfo.fillFromInputFile(ftp2fn(efTPR, NFILE, fnm));
635 gmx_mtop_generate_local_top(*topInfo.mtop(), &top, ir->efep != efepNO);
637 nbounds = get_bounds(&bounds, &index, &pair, &npairs,
639 snew(violaver, npairs);
640 out_disre = xvgropen(opt2fn("-o", NFILE, fnm), "Sum of Violations",
641 "Time (ps)", "nm", oenv);
642 xvgr_legend(out_disre, 2, drleg, oenv);
645 fp_pairs = xvgropen(opt2fn("-pairs", NFILE, fnm), "Pair Distances",
646 "Time (ps)", "Distance (nm)", oenv);
647 if (output_env_get_print_xvgr_codes(oenv))
649 fprintf(fp_pairs, "@ subtitle \"averaged (tau=%g) and instantaneous\"\n",
655 /* Initiate counters */
660 /* This loop searches for the first frame (when -b option is given),
661 * or when this has been found it reads just one energy frame
665 bCont = do_enx(fp, &fr);
668 timecheck = check_times(fr.t);
671 while (bCont && (timecheck < 0));
673 if ((timecheck == 0) && bCont)
676 * Define distance restraint legends. Can only be done after
677 * the first frame has been read... (Then we know how many there are)
679 blk_disre = find_block_id_enxframe(&fr, enxDISRE, nullptr);
680 if (bDisRe && bDRAll && !leg && blk_disre)
685 fa = top.idef.il[F_DISRES].iatoms;
686 ip = top.idef.iparams;
687 if (blk_disre->nsub != 2 ||
688 (blk_disre->sub[0].nr != blk_disre->sub[1].nr) )
690 gmx_incons("Number of disre sub-blocks not equal to 2");
693 ndisre = blk_disre->sub[0].nr;
694 if (ndisre != top.idef.il[F_DISRES].nr/3)
696 gmx_fatal(FARGS, "Number of disre pairs in the energy file (%d) does not match the number in the run input file (%d)\n",
697 ndisre, top.idef.il[F_DISRES].nr/3);
699 snew(pairleg, ndisre);
701 for (i = 0; i < ndisre; i++)
703 snew(pairleg[i], 30);
706 mtopGetAtomAndResidueName(topInfo.mtop(), j, &molb, &anm_j, &resnr_j, &resnm_j, nullptr);
707 mtopGetAtomAndResidueName(topInfo.mtop(), k, &molb, &anm_k, &resnr_k, &resnm_k, nullptr);
708 sprintf(pairleg[i], "%d %s %d %s (%d)",
709 resnr_j, anm_j, resnr_k, anm_k,
710 ip[fa[3*i]].disres.label);
712 set = select_it(ndisre, pairleg, &nset);
714 for (i = 0; (i < nset); i++)
717 sprintf(leg[2*i], "a %s", pairleg[set[i]]);
718 snew(leg[2*i+1], 32);
719 sprintf(leg[2*i+1], "i %s", pairleg[set[i]]);
721 xvgr_legend(fp_pairs, 2*nset, leg, oenv);
725 * Printing time, only when we do not want to skip frames
727 if (!skip || teller % skip == 0)
731 /*******************************************
732 * D I S T A N C E R E S T R A I N T S
733 *******************************************/
736 GMX_RELEASE_ASSERT(blk_disre != nullptr, "Trying to dereference NULL blk_disre pointer");
738 float *disre_rt = blk_disre->sub[0].fval;
739 float *disre_rm3tav = blk_disre->sub[1].fval;
741 double *disre_rt = blk_disre->sub[0].dval;
742 double *disre_rm3tav = blk_disre->sub[1].dval;
745 print_time(out_disre, fr.t);
746 if (violaver == nullptr)
748 snew(violaver, ndisre);
751 /* Subtract bounds from distances, to calculate violations */
752 calc_violations(disre_rt, disre_rm3tav,
753 nbounds, pair, bounds, violaver, &sumt, &sumaver);
755 fprintf(out_disre, " %8.4f %8.4f\n", sumaver, sumt);
758 print_time(fp_pairs, fr.t);
759 for (i = 0; (i < nset); i++)
762 fprintf(fp_pairs, " %8.4f", mypow(disre_rm3tav[sss], minthird));
763 fprintf(fp_pairs, " %8.4f", disre_rt[sss]);
765 fprintf(fp_pairs, "\n");
771 /*******************************************
773 *******************************************/
776 t_enxblock *blk = find_block_id_enxframe(&fr, enx_i, nullptr);
781 gmx_fatal(FARGS, "Orientational restraints read in incorrectly.");
784 if (blk->sub[0].nr != nor)
786 gmx_fatal(FARGS, "Number of orientation restraints in energy file (%d) does not match with the topology (%d)", blk->sub[0].nr, nor);
790 for (i = 0; i < nor; i++)
792 orient[i] += blk_value(blk, 0, i);
797 for (i = 0; i < nor; i++)
799 real v = blk_value(blk, 0, i);
800 odrms[i] += gmx::square(v - oobs[i]);
805 fprintf(fort, " %10f", fr.t);
806 for (i = 0; i < norsel; i++)
808 fprintf(fort, " %g", blk_value(blk, 0, orsel[i]));
814 fprintf(fodt, " %10f", fr.t);
815 for (i = 0; i < norsel; i++)
817 fprintf(fodt, " %g", blk_value(blk, 0, orsel[i])-oobs[orsel[i]]);
823 blk = find_block_id_enxframe(&fr, enxORT, nullptr);
828 gmx_fatal(FARGS, "Orientational restraints read in incorrectly");
831 if (blk->sub[0].nr != nex*12)
833 gmx_fatal(FARGS, "Number of orientation experiments in energy file (%d) does not match with the topology (%d)",
834 blk->sub[0].nr/12, nex);
836 fprintf(foten, " %10f", fr.t);
837 for (i = 0; i < nex; i++)
839 for (j = 0; j < (bOvec ? 12 : 3); j++)
841 fprintf(foten, " %g", blk_value(blk, 0, i*12+j));
844 fprintf(foten, "\n");
851 while (bCont && (timecheck == 0));
854 fprintf(stderr, "\n");
858 xvgrclose(out_disre);
876 FILE *out = xvgropen(opt2fn("-ora", NFILE, fnm),
877 "Average calculated orientations",
878 "Restraint label", "", oenv);
879 if (bOrinst && output_env_get_print_xvgr_codes(oenv))
881 fprintf(out, "%s", orinst_sub);
883 for (i = 0; i < nor; i++)
885 fprintf(out, "%5d %g\n", or_label[i], orient[i]/real(norfr));
891 FILE *out = xvgropen(opt2fn("-oda", NFILE, fnm),
892 "Average restraint deviation",
893 "Restraint label", "", oenv);
894 if (bOrinst && output_env_get_print_xvgr_codes(oenv))
896 fprintf(out, "%s", orinst_sub);
898 for (i = 0; i < nor; i++)
900 fprintf(out, "%5d %g\n", or_label[i], orient[i]/real(norfr)-oobs[i]);
906 FILE *out = xvgropen(opt2fn("-odr", NFILE, fnm),
907 "RMS orientation restraint deviations",
908 "Restraint label", "", oenv);
909 if (bOrinst && output_env_get_print_xvgr_codes(oenv))
911 fprintf(out, "%s", orinst_sub);
913 for (i = 0; i < nor; i++)
915 fprintf(out, "%5d %g\n", or_label[i], std::sqrt(odrms[i]/real(norfr)));
919 // Clean up orires variables.
932 analyse_disre(opt2fn("-viol", NFILE, fnm),
933 teller_disre, violaver, bounds, index, pair, nbounds, oenv);
936 const char *nxy = "-nxy";
938 do_view(oenv, opt2fn_null("-ora", NFILE, fnm), nxy);
939 do_view(oenv, opt2fn_null("-ort", NFILE, fnm), nxy);
940 do_view(oenv, opt2fn_null("-oda", NFILE, fnm), nxy);
941 do_view(oenv, opt2fn_null("-odr", NFILE, fnm), nxy);
942 do_view(oenv, opt2fn_null("-odt", NFILE, fnm), nxy);
943 do_view(oenv, opt2fn_null("-oten", NFILE, fnm), nxy);
945 output_env_done(oenv);