2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010,2011,2012,2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
37 * Implements classes in plot.h.
39 * \ingroup module_analysisdata
40 * \author Teemu Murtola <teemu.murtola@gmail.com>
52 #include "gromacs/analysisdata/dataframe.h"
53 #include "gromacs/fileio/gmxfio.h"
54 #include "gromacs/fileio/oenv.h"
55 #include "gromacs/fileio/xvgr.h"
56 #include "gromacs/math/vec.h"
57 #include "gromacs/options/basicoptions.h"
58 #include "gromacs/options/ioptionscontainer.h"
59 #include "gromacs/options/timeunitmanager.h"
60 #include "gromacs/selection/selectioncollection.h"
61 #include "gromacs/utility/exceptions.h"
62 #include "gromacs/utility/gmxassert.h"
63 #include "gromacs/utility/programcontext.h"
64 #include "gromacs/utility/stringutil.h"
65 #include "gromacs/utility/unique_cptr.h"
70 //! Enum values for plot formats.
71 const char *const g_plotFormats
[] = {
72 "none", "xmgrace", "xmgr"
80 /********************************************************************
81 * AnalysisDataPlotSettings
84 AnalysisDataPlotSettings::AnalysisDataPlotSettings()
85 : selections_(nullptr), timeUnit_(TimeUnit_Default
), plotFormat_(1)
90 AnalysisDataPlotSettings::setSelectionCollection(const SelectionCollection
*selections
)
92 selections_
= selections
;
97 AnalysisDataPlotSettings::initOptions(IOptionsContainer
*options
)
99 options
->addOption(EnumIntOption("xvg").enumValue(g_plotFormats
)
101 .description("Plot formatting"));
105 /********************************************************************
106 * AbstractPlotModule::Impl
109 class AbstractPlotModule::Impl
112 explicit Impl(const AnalysisDataPlotSettings
&settings
);
117 AnalysisDataPlotSettings settings_
;
118 std::string filename_
;
123 bool bErrorsAsSeparateColumn_
;
125 std::string subtitle_
;
128 std::vector
<std::string
> legend_
;
134 AbstractPlotModule::Impl::Impl(const AnalysisDataPlotSettings
&settings
)
135 : settings_(settings
), fp_(nullptr), bPlain_(false), bOmitX_(false),
136 bErrorsAsSeparateColumn_(false), xscale_(1.0)
138 strcpy(xformat_
, "%11.3f");
139 strcpy(yformat_
, " %8.3f");
142 AbstractPlotModule::Impl::~Impl()
149 AbstractPlotModule::Impl::closeFile()
166 /********************************************************************
170 AbstractPlotModule::AbstractPlotModule()
171 : impl_(new Impl(AnalysisDataPlotSettings()))
175 AbstractPlotModule::AbstractPlotModule(const AnalysisDataPlotSettings
&settings
)
176 : impl_(new Impl(settings
))
181 AbstractPlotModule::~AbstractPlotModule()
187 AbstractPlotModule::setSettings(const AnalysisDataPlotSettings
&settings
)
189 impl_
->settings_
= settings
;
194 AbstractPlotModule::setFileName(const std::string
&filename
)
196 impl_
->filename_
= filename
;
201 AbstractPlotModule::setPlainOutput(bool bPlain
)
203 impl_
->bPlain_
= bPlain
;
208 AbstractPlotModule::setErrorsAsSeparateColumn(bool bSeparate
)
210 impl_
->bErrorsAsSeparateColumn_
= bSeparate
;
215 AbstractPlotModule::setOmitX(bool bOmitX
)
217 impl_
->bOmitX_
= bOmitX
;
222 AbstractPlotModule::setTitle(const char *title
)
224 impl_
->title_
= title
;
228 AbstractPlotModule::setTitle(const std::string
&title
)
230 impl_
->title_
= title
;
235 AbstractPlotModule::setSubtitle(const char *subtitle
)
237 impl_
->subtitle_
= subtitle
;
242 AbstractPlotModule::setSubtitle(const std::string
&subtitle
)
244 impl_
->subtitle_
= subtitle
;
249 AbstractPlotModule::setXLabel(const char *label
)
251 impl_
->xlabel_
= label
;
256 AbstractPlotModule::setXAxisIsTime()
258 TimeUnitManager
manager(impl_
->settings_
.timeUnit());
259 impl_
->xlabel_
= formatString("Time (%s)", manager
.timeUnitAsString());
260 impl_
->xscale_
= manager
.inverseTimeScaleFactor();
265 AbstractPlotModule::setYLabel(const char *label
)
267 impl_
->ylabel_
= label
;
272 AbstractPlotModule::setLegend(int nsets
, const char * const *setname
)
274 impl_
->legend_
.reserve(impl_
->legend_
.size() + nsets
);
275 for (int i
= 0; i
< nsets
; ++i
)
277 appendLegend(setname
[i
]);
283 AbstractPlotModule::appendLegend(const char *setname
)
285 impl_
->legend_
.emplace_back(setname
);
290 AbstractPlotModule::appendLegend(const std::string
&setname
)
292 impl_
->legend_
.push_back(setname
);
297 AbstractPlotModule::setXFormat(int width
, int precision
, char format
)
299 GMX_RELEASE_ASSERT(width
>= 0 && precision
>= 0
300 && width
<= 99 && precision
<= 99,
301 "Invalid width or precision");
302 GMX_RELEASE_ASSERT(strchr("eEfFgG", format
) != nullptr,
303 "Invalid format specifier");
304 sprintf(impl_
->xformat_
, "%%%d.%d%c", width
, precision
, format
);
309 AbstractPlotModule::setYFormat(int width
, int precision
, char format
)
311 GMX_RELEASE_ASSERT(width
>= 0 && precision
>= 0
312 && width
<= 99 && precision
<= 99,
313 "Invalid width or precision");
314 GMX_RELEASE_ASSERT(strchr("eEfFgG", format
) != nullptr,
315 "Invalid format specifier");
316 sprintf(impl_
->yformat_
, " %%%d.%d%c", width
, precision
, format
);
321 AbstractPlotModule::flags() const
323 return efAllowMissing
| efAllowMulticolumn
| efAllowMultipoint
324 | efAllowMultipleDataSets
;
329 AbstractPlotModule::dataStarted(AbstractAnalysisData
* /* data */)
331 if (!impl_
->filename_
.empty())
335 impl_
->fp_
= gmx_fio_fopen(impl_
->filename_
.c_str(), "w");
339 time_unit_t time_unit
340 = static_cast<time_unit_t
>(impl_
->settings_
.timeUnit() + 1); // NOLINT(misc-misplaced-widening-cast)
341 xvg_format_t xvg_format
342 = (impl_
->settings_
.plotFormat() > 0
343 ? static_cast<xvg_format_t
>(impl_
->settings_
.plotFormat())
345 gmx_output_env_t
*oenv
;
346 output_env_init(&oenv
, getProgramContext(), time_unit
, FALSE
, xvg_format
, 0);
347 const unique_cptr
<gmx_output_env_t
, output_env_done
> oenvGuard(oenv
);
348 impl_
->fp_
= xvgropen(impl_
->filename_
.c_str(), impl_
->title_
.c_str(),
349 impl_
->xlabel_
, impl_
->ylabel_
,
351 const SelectionCollection
*selections
352 = impl_
->settings_
.selectionCollection();
353 if (selections
!= nullptr && output_env_get_xvg_format(oenv
) != exvgNONE
)
355 selections
->printXvgrInfo(impl_
->fp_
);
357 if (!impl_
->subtitle_
.empty())
359 xvgr_subtitle(impl_
->fp_
, impl_
->subtitle_
.c_str(), oenv
);
361 if (output_env_get_print_xvgr_codes(oenv
)
362 && !impl_
->legend_
.empty())
364 std::vector
<const char *> legend
;
365 legend
.reserve(impl_
->legend_
.size());
366 for (size_t i
= 0; i
< impl_
->legend_
.size(); ++i
)
368 legend
.push_back(impl_
->legend_
[i
].c_str());
370 xvgr_legend(impl_
->fp_
, legend
.size(), legend
.data(), oenv
);
378 AbstractPlotModule::frameStarted(const AnalysisDataFrameHeader
&frame
)
386 std::fprintf(impl_
->fp_
, impl_
->xformat_
, frame
.x() * impl_
->xscale_
);
392 AbstractPlotModule::frameFinished(const AnalysisDataFrameHeader
& /*header*/)
398 std::fprintf(impl_
->fp_
, "\n");
403 AbstractPlotModule::dataFinished()
410 AbstractPlotModule::isFileOpen() const
412 return impl_
->fp_
!= nullptr;
417 AbstractPlotModule::writeValue(const AnalysisDataValue
&value
) const
419 GMX_ASSERT(isFileOpen(), "File not opened, but write attempted");
420 const real y
= value
.isSet() ? value
.value() : 0.0;
421 std::fprintf(impl_
->fp_
, impl_
->yformat_
, y
);
422 if (impl_
->bErrorsAsSeparateColumn_
)
424 const real dy
= value
.isSet() ? value
.error() : 0.0;
425 std::fprintf(impl_
->fp_
, impl_
->yformat_
, dy
);
430 /********************************************************************
434 AnalysisDataPlotModule::AnalysisDataPlotModule()
438 AnalysisDataPlotModule::AnalysisDataPlotModule(
439 const AnalysisDataPlotSettings
&settings
)
440 : AbstractPlotModule(settings
)
446 AnalysisDataPlotModule::pointsAdded(const AnalysisDataPointSetRef
&points
)
452 for (int i
= 0; i
< points
.columnCount(); ++i
)
454 writeValue(points
.values()[i
]);
459 /********************************************************************
460 * DataVectorPlotModule
463 AnalysisDataVectorPlotModule::AnalysisDataVectorPlotModule()
465 for (int i
= 0; i
< DIM
; ++i
)
469 bWrite_
[DIM
] = false;
473 AnalysisDataVectorPlotModule::AnalysisDataVectorPlotModule(
474 const AnalysisDataPlotSettings
&settings
)
475 : AbstractPlotModule(settings
)
477 for (int i
= 0; i
< DIM
; ++i
)
481 bWrite_
[DIM
] = false;
486 AnalysisDataVectorPlotModule::setWriteX(bool bWrite
)
488 bWrite_
[XX
] = bWrite
;
493 AnalysisDataVectorPlotModule::setWriteY(bool bWrite
)
495 bWrite_
[YY
] = bWrite
;
500 AnalysisDataVectorPlotModule::setWriteZ(bool bWrite
)
502 bWrite_
[ZZ
] = bWrite
;
507 AnalysisDataVectorPlotModule::setWriteNorm(bool bWrite
)
509 bWrite_
[DIM
] = bWrite
;
514 AnalysisDataVectorPlotModule::setWriteMask(const bool bWrite
[DIM
+ 1])
516 for (int i
= 0; i
< DIM
+ 1; ++i
)
518 bWrite_
[i
] = bWrite
[i
];
524 AnalysisDataVectorPlotModule::pointsAdded(const AnalysisDataPointSetRef
&points
)
526 if (points
.firstColumn() % DIM
!= 0 || points
.columnCount() % DIM
!= 0)
528 GMX_THROW(APIError("Partial data points"));
534 for (int i
= 0; i
< points
.columnCount(); i
+= 3)
536 for (int d
= 0; d
< DIM
; ++d
)
540 writeValue(points
.values()[i
+ d
]);
545 const rvec y
= { points
.y(i
), points
.y(i
+ 1), points
.y(i
+ 2) };
546 AnalysisDataValue
value(norm(y
));