CmdLine.cpp 12.9 KB
Newer Older
mvalle's avatar
mvalle committed
1
2
3
4
5
6
7

#include <iostream>
#include <climits>
#include <vector>
#include "CmdLine.h"
#include "simpleopt/SimpleOpt.h"
#include "Exceptions.h"
8
#include "ParseParameters.h"
mvalle's avatar
mvalle committed
9

mvalle's avatar
mvalle committed
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/// Implementation of the CmdLine class.
///
struct CmdLine::CmdLineImpl
{
	/// Return the text corresponding to an error code.
	///
	/// @param[in] aOptParser The command line parser object
	///
	/// @return The human readable error message
	///
	const char *getLastErrorText(CSimpleOpt& aOptParser);

	/// Print the help about the parameters.
	///
	/// @param[in] aParserOptions The table of options definitions
	///
	void showHelp(const CSimpleOpt::SOption *aParserOptions);
};

const char *CmdLine::CmdLineImpl::getLastErrorText(CSimpleOpt& aOptParser)
mvalle's avatar
mvalle committed
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
    switch(aOptParser.LastError())
	{
    case SO_SUCCESS:            return "Success";
    case SO_OPT_INVALID:        return "Unrecognized option";
    case SO_OPT_MULTIPLE:       return "Option matched multiple strings";
    case SO_ARG_INVALID:        return "Option does not accept argument";
    case SO_ARG_INVALID_TYPE:   return "Invalid argument format";
    case SO_ARG_MISSING:        return "Required argument is missing";
    case SO_ARG_INVALID_DATA:   return "Invalid argument data";
    default:					return "Unknown error";
    }
}


mvalle's avatar
mvalle committed
45
void CmdLine::CmdLineImpl::showHelp(const CSimpleOpt::SOption *aParserOptions)
mvalle's avatar
mvalle committed
46
{
mvalle's avatar
mvalle committed
47
	size_t i, j, cnt;
mvalle's avatar
mvalle committed
48
49
50
51
52
53
54
55
56
57
58

	// Count entries and create an indicator array
	for(cnt=0; aParserOptions[cnt].pszArg != NULL; ++cnt) {}
	std::vector<bool> done(cnt, false);

	// For each different option
	for(i=0; i < cnt; ++i)
	{
		if(done[i]) continue;
		done[i] = true;

59
		std::cout << aParserOptions[i].pszArg;
mvalle's avatar
mvalle committed
60
61
62
63
		for(j=i+1; j < cnt; ++j)
		{
			if(done[j] || aParserOptions[j].nId != aParserOptions[i].nId) continue;
			done[j] = true;
64
			std::cout << "  " << aParserOptions[j].pszArg;
mvalle's avatar
mvalle committed
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
		}

		// Translate the kind of argument
		const char* type = "";
		switch(aParserOptions[i].nArgType)
		{
		case SO_NONE:   
			type = "(no argument)";
			break;

		case SO_REQ_SEP:
		case SO_REQ_CMB:
			type = "(required argument)";
			break;

		case SO_OPT:
			type = "(optional argument)";
			break;

		case SO_MULTI:
			type = "(multiple arguments)";
			break;
mvalle's avatar
mvalle committed
87
88
89
90

		default:
			type = "(?)";
			break;
mvalle's avatar
mvalle committed
91
92
		}

93
94
		std::cout << " " << type << std::endl;
		std::cout << "        " << aParserOptions[i].pszHelp << std::endl << std::endl;
mvalle's avatar
mvalle committed
95
96
97
	}
}

mvalle's avatar
mvalle committed
98
99
100
101
CmdLine::~CmdLine()
{
	delete mCmdLineImpl;
}
mvalle's avatar
mvalle committed
102
103
104

void CmdLine::parseCmdLine(int aCnt, char **aVal)
{
mvalle's avatar
mvalle committed
105
106
107
108
109
110
	// Create the class implementation so it is not visible outside
	if(!mCmdLineImpl)
	{
		mCmdLineImpl = new CmdLine::CmdLineImpl;
	}

111
	// Setup the command line parser. First the identifiers for the various options
mvalle's avatar
mvalle committed
112
113
114
115
116
117
	enum {
		OPT_VERBOSE,
		OPT_QUIET,
		OPT_HELP,
		OPT_SEED,
		OPT_BRANCH,
mvalle's avatar
mvalle committed
118
119
		OPT_BRANCH_START,
		OPT_BRANCH_END,
mvalle's avatar
mvalle committed
120
121
122
123
124
125
126
127
128
129
		OPT_IGNORE_FREQ,
		OPT_EXPORT,
		OPT_NOT_REDUCE,
		OPT_TIMES_FROM_FILE,
		OPT_ONE_STEP,
		OPT_COMP_TIMES,
		OPT_TRACE,
		OPT_FORCE_SERIAL,
		OPT_BRANCH_FROM_FILE,
		OPT_ONE_HYP_ONLY,
mvalle's avatar
mvalle committed
130
		OPT_INIT_H0_FROM_H1,
mvalle's avatar
mvalle committed
131
		OPT_OPTIM_ALGO,
132
		OPT_DELTA_VAL,
133
		OPT_INIT_PARAM,
134
		OPT_INIT_DEFAULT,
135
		OPT_EXTRA_DEBUG,
136
		OPT_REL_ERROR,
mvalle's avatar
mvalle committed
137
		OPT_OUT_RESULTS,
138
139
		OPT_CLEAN_DATA,
		OPT_NO_PRE_STOP
mvalle's avatar
mvalle committed
140
141
	};

142
	// Then the definitions of each command line option
mvalle's avatar
mvalle committed
143
	CSimpleOpt::SOption parser_options[] = {
144
		{ OPT_VERBOSE,			"-d",					SO_REQ_SEP, "Verbosity level (0: none; 1: results only; 2: normal info; 3: MPI trace; 4: more debug) (default: 1)" },
mvalle's avatar
mvalle committed
145
146
147
148
149
150
151
152
153
154
		{ OPT_VERBOSE,			"--debug",				SO_REQ_SEP, "" },
		{ OPT_VERBOSE,			"-v",					SO_REQ_SEP, "" },
		{ OPT_VERBOSE,			"--verbose",			SO_REQ_SEP, "" },
		{ OPT_QUIET,			"-q",					SO_NONE,    "No messages except results" },
		{ OPT_QUIET,			"--quiet",				SO_NONE,    "" },
		{ OPT_HELP,				"-?",					SO_NONE,    "This help" },
		{ OPT_HELP,				"-h",					SO_NONE,    "" },
		{ OPT_HELP,				"--help",				SO_NONE,    "" },
		{ OPT_SEED,				"-s",					SO_REQ_SEP, "Random number generator seed (0 < seed < 1000000000)" },
		{ OPT_SEED,				"--seed",				SO_REQ_SEP, "" },
mvalle's avatar
mvalle committed
155
		{ OPT_BRANCH,			"-b",					SO_REQ_SEP, "Do only this branch as foreground branch (count from 0)" },
mvalle's avatar
mvalle committed
156
		{ OPT_BRANCH,			"--branch",				SO_REQ_SEP, "" },
mvalle's avatar
mvalle committed
157
158
159
160
161
		{ OPT_BRANCH_START,		"-bs",					SO_REQ_SEP, "Start computing from this branch as foreground one (count from 0) (default: first one)" },
		{ OPT_BRANCH_START,		"--branch-start",		SO_REQ_SEP, "" },
		{ OPT_BRANCH_END,		"-be",					SO_REQ_SEP, "End computing at this branch as foreground one (count from 0) (default: last one)" },
		{ OPT_BRANCH_END,		"--branch-end",			SO_REQ_SEP, "" },
		{ OPT_IGNORE_FREQ,		"-i",					SO_NONE,	"Ignore computed codon frequency and set all of them to 1/61" },
mvalle's avatar
mvalle committed
162
163
164
165
166
167
		{ OPT_IGNORE_FREQ,		"--ignore-freq",		SO_NONE,	"" },
		{ OPT_EXPORT,			"-e",					SO_REQ_SEP,	"Export forest in GML format (if %03d or @03d is present, one is created for each fg branch)" },
		{ OPT_EXPORT,			"--export",				SO_REQ_SEP,	"" },
		{ OPT_NOT_REDUCE,		"-nr",					SO_NONE,	"Do not reduce forest by merging common subtrees" },
		{ OPT_NOT_REDUCE,		"--no-reduce",			SO_NONE,	"" },
		{ OPT_TIMES_FROM_FILE,	"-l",					SO_NONE,	"Initial branch lengths from tree file" },
168
		{ OPT_TIMES_FROM_FILE,	"--lengths-from-file",	SO_NONE,	"" },
mvalle's avatar
mvalle committed
169
		{ OPT_TIMES_FROM_FILE,	"--times-from-file",	SO_NONE,	"" },
mvalle's avatar
mvalle committed
170
171
172
173
174
175
176
177
178
179
180
181
		{ OPT_ONE_STEP,			"-o",					SO_NONE,	"Only the initial step is performed (no maximization)" },
		{ OPT_ONE_STEP,			"--initial-step",		SO_NONE,	"" },
		{ OPT_COMP_TIMES,		"-c",					SO_REQ_SEP,	"Export the computed times from H0 if 0, H1 if 1, otherwise the one read in the phylo tree" },
		{ OPT_COMP_TIMES,		"--export-comp-times",	SO_REQ_SEP,	"" },
		{ OPT_TRACE,			"-r",					SO_NONE,	"Trace the maximization run" },
		{ OPT_TRACE,			"--trace",				SO_NONE,	"" },
		{ OPT_FORCE_SERIAL,		"-np",					SO_NONE,	"Don't use parallel execution" },
		{ OPT_FORCE_SERIAL,		"--no-parallel",		SO_NONE,	"" },
		{ OPT_BRANCH_FROM_FILE,	"-bf",					SO_NONE,	"Do only the branch marked in the file as foreground branch" },
		{ OPT_BRANCH_FROM_FILE,	"--branch-from-file",	SO_NONE,	"" },
		{ OPT_ONE_HYP_ONLY,		"-hy",					SO_REQ_SEP,	"Compute only H0 if 0, H1 if 1" },
		{ OPT_ONE_HYP_ONLY,		"--only-hyp",			SO_REQ_SEP,	"" },
mvalle's avatar
mvalle committed
182
183
		{ OPT_INIT_H0_FROM_H1,	"-i1",					SO_NONE,	"Start H0 optimization from H1 results" },
		{ OPT_INIT_H0_FROM_H1,	"--init-from-h1",		SO_NONE,	"" },
184
		{ OPT_OPTIM_ALGO,		"-m",					SO_REQ_SEP,	"Optimizer algorithm (0:LBFGS, 1:VAR1, 2:VAR2, 3:SLSQP, 11:BOBYQA, 22:FromCodeML) (default: 0)" },
mvalle's avatar
mvalle committed
185
		{ OPT_OPTIM_ALGO,		"--maximizer",			SO_REQ_SEP,	"" },
186
		{ OPT_DELTA_VAL,		"-sd",					SO_REQ_SEP,	"Delta used in gradient computation (default: 1.49e-8)" },
mvalle's avatar
mvalle committed
187
		{ OPT_DELTA_VAL,		"--small-diff",			SO_REQ_SEP,	"" },
188
189
190
191
		{ OPT_INIT_PARAM,		"-p",					SO_REQ_SEP,	"Pass initialization parameter in the form: P=value (P: w0, k, p0, p1, w2)" },
		{ OPT_INIT_PARAM,		"--init-param",			SO_REQ_SEP,	"" },
		{ OPT_INIT_DEFAULT,		"-ic",					SO_NONE,	"Start from default parameter values and times from tree file" },
		{ OPT_INIT_DEFAULT,		"--init-default",		SO_NONE,	"" },
mvalle's avatar
mvalle committed
192
		{ OPT_EXTRA_DEBUG,		"-x",					SO_REQ_SEP,	"Extra debug parameter (zero disables it)" },
193
		{ OPT_EXTRA_DEBUG,		"--extra-debug",		SO_REQ_SEP,	"" },
mvalle's avatar
mvalle committed
194
		{ OPT_REL_ERROR,		"-re",					SO_REQ_SEP,	"Relative error where to stop maximization (default: 1e-3)" },
195
		{ OPT_REL_ERROR,		"--relative-error",		SO_REQ_SEP,	"" },
mvalle's avatar
mvalle committed
196
		{ OPT_OUT_RESULTS,		"-ou",					SO_REQ_SEP,	"Write results formatted to this file" },
197
		{ OPT_OUT_RESULTS,		"--output",				SO_REQ_SEP,	"" },
mvalle's avatar
mvalle committed
198
199
		{ OPT_CLEAN_DATA,		"-cl",					SO_NONE,	"Remove ambiguous or missing sites from the MSA (default: no)" },
		{ OPT_CLEAN_DATA,		"--clean-data",			SO_NONE,	"" },
mvalle's avatar
mvalle committed
200
		{ OPT_NO_PRE_STOP,		"-ps",					SO_NONE,	"Don't stop H0 maximization even if it cannot satisfy LRT (default: stop)" },
201
		{ OPT_NO_PRE_STOP,		"--no-pre-stop",		SO_NONE,	"" },
mvalle's avatar
mvalle committed
202
203
		SO_END_OF_OPTIONS
	};
204
	
mvalle's avatar
mvalle committed
205
	// Setup the usage string
206
	const char* usage_msg = "FastCodeML [options] tree_file alignment_file";
mvalle's avatar
mvalle committed
207
208
209
210
211
212
213

    // Declare our options parser, pass in the arguments from main as well as our array of valid options.
    CSimpleOpt args(aCnt, aVal, parser_options, SO_O_NOSLASH);

    // While there are arguments left to process
    while(args.Next())
	{
214
		// Signal error if option invalid
mvalle's avatar
mvalle committed
215
216
		if(args.LastError() == SO_OPT_INVALID)
		{
217
			std::ostringstream o;
mvalle's avatar
mvalle committed
218
			o << "Error: " << mCmdLineImpl->getLastErrorText(args) << ": " << args.OptionText() << std::endl;
219
			throw FastCodeMLFatal(o);
mvalle's avatar
mvalle committed
220
221
222
        }
        if(args.LastError() != SO_SUCCESS)
		{
223
			std::ostringstream o;
mvalle's avatar
mvalle committed
224
            o << "Error: " << mCmdLineImpl->getLastErrorText(args) << " for: " << args.OptionText() << std::endl;
225
			throw FastCodeMLFatal(o);
mvalle's avatar
mvalle committed
226
227
        }

228
		// Get the various options
mvalle's avatar
mvalle committed
229
230
231
232
		int tmpi;
		switch(args.OptionId())
		{
		case OPT_VERBOSE:
233
			if(mVerboseLevel == VERBOSE_NONE) break; // Ignore option if quiet is set
mvalle's avatar
mvalle committed
234
235
			tmpi = atoi(args.OptionArg());
			if(tmpi < 0) throw FastCodeMLFatal("Invalid verbose level");
mvalle's avatar
mvalle committed
236
			mVerboseLevel = static_cast<unsigned int>(tmpi);
mvalle's avatar
mvalle committed
237
238
239
			break;

		case OPT_QUIET:
240
			mVerboseLevel = VERBOSE_NONE;
mvalle's avatar
mvalle committed
241
242
			break;

mvalle's avatar
mvalle committed
243
		default:
mvalle's avatar
mvalle committed
244
		case OPT_HELP:
245
246
			std::cout << "Usage:" << std::endl;
			std::cout << "    " << usage_msg << std::endl << std::endl;
mvalle's avatar
mvalle committed
247
			mCmdLineImpl->showHelp(parser_options);
mvalle's avatar
mvalle committed
248
249
250
251
252
			throw FastCodeMLSuccess();

		case OPT_SEED:
			tmpi = atoi(args.OptionArg());
			if(tmpi < 0) throw FastCodeMLFatal("Invalid seed value");
mvalle's avatar
mvalle committed
253
			mSeed = static_cast<unsigned int>(tmpi);
mvalle's avatar
mvalle committed
254
255
256
257
258
			break;

		case OPT_BRANCH:
			tmpi = atoi(args.OptionArg());
			if(tmpi < 0) throw FastCodeMLFatal("Invalid branch value");
mvalle's avatar
mvalle committed
259
260
261
262
263
264
265
266
267
268
269
270
271
			mBranchStart = mBranchEnd = static_cast<unsigned int>(tmpi);
			break;

		case OPT_BRANCH_START:
			tmpi = atoi(args.OptionArg());
			if(tmpi < 0) throw FastCodeMLFatal("Invalid start branch value");
			mBranchStart = static_cast<unsigned int>(tmpi);
			break;

		case OPT_BRANCH_END:
			tmpi = atoi(args.OptionArg());
			if(tmpi < 0) throw FastCodeMLFatal("Invalid end branch value");
			mBranchEnd = static_cast<unsigned int>(tmpi);
mvalle's avatar
mvalle committed
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
			break;

		case OPT_IGNORE_FREQ:
			mIgnoreFreq = true;
			break;

		case OPT_EXPORT:
			mGraphFile = args.OptionArg();
			break;

		case OPT_NOT_REDUCE:
			mDoNotReduceForest = true;
			break;

		case OPT_TIMES_FROM_FILE:
287
			mBranchLengthsFromFile = true;
mvalle's avatar
mvalle committed
288
289
290
291
292
293
294
			break;

		case OPT_ONE_STEP:
			mNoMaximization = true;
			break;

		case OPT_COMP_TIMES:
mvalle's avatar
mvalle committed
295
			mExportComputedTimes = static_cast<unsigned int>(atoi(args.OptionArg()));
mvalle's avatar
mvalle committed
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
			if(mExportComputedTimes > 1) mExportComputedTimes = UINT_MAX;
			break;

		case OPT_TRACE:
			mTrace = true;
			break;

		case OPT_FORCE_SERIAL:
			mForceSerial = true;
			break;

		case OPT_BRANCH_FROM_FILE:
			mBranchFromFile = true;
			break;

		case OPT_ONE_HYP_ONLY:
mvalle's avatar
mvalle committed
312
			mComputeHypothesis = static_cast<unsigned int>(atoi(args.OptionArg()));
mvalle's avatar
mvalle committed
313
314
315
			if(mComputeHypothesis != 0 && mComputeHypothesis != 1) throw FastCodeMLFatal("Invalid hypothesis specified");
			break;

mvalle's avatar
mvalle committed
316
317
		case OPT_INIT_H0_FROM_H1:
			mInitH0fromH1 = true;
mvalle's avatar
mvalle committed
318
319
320
			break;

		case OPT_OPTIM_ALGO:
mvalle's avatar
mvalle committed
321
			mOptimizationAlgo = static_cast<unsigned int>(atoi(args.OptionArg()));
mvalle's avatar
mvalle committed
322
323
324
325
326
			break;

		case OPT_DELTA_VAL:
			mDeltaValueForGradient = atof(args.OptionArg());
			if(mDeltaValueForGradient < 0.0) mDeltaValueForGradient = 0.0;
mvalle's avatar
mvalle committed
327
			break;
328

329
		case OPT_INIT_PARAM:
330
			ParseParameters::getInstance()->addParameter(args.OptionArg());
331
332
333
334
			mInitFromParams = true;
			break;

		case OPT_INIT_DEFAULT:
335
			mBranchLengthsFromFile = true;
336
			mInitFromParams = true;
337
			break;
338
339

		case OPT_EXTRA_DEBUG:
mvalle's avatar
mvalle committed
340
			mExtraDebug = static_cast<unsigned int>(atoi(args.OptionArg()));
341
			break;
342
343
344

		case OPT_REL_ERROR:
			mRelativeError = atof(args.OptionArg());
mvalle's avatar
mvalle committed
345
			if(mRelativeError <= 0.0) throw FastCodeMLFatal("Invalid relative error value");
346
			break;
347

348
349
350
		case OPT_OUT_RESULTS:
			mResultsFile = args.OptionArg();
			break;
mvalle's avatar
mvalle committed
351
352
353
354

		case OPT_CLEAN_DATA:
			mCleanData = true;
			break;
355
356
357
358

		case OPT_NO_PRE_STOP:
			mStopIfNotLRT = false;
			break;
mvalle's avatar
mvalle committed
359
360
		}
	}
361

mvalle's avatar
mvalle committed
362
363
364
365
	// Parse the file arguments
	switch(args.FileCount())
	{
	case 0:
366
		std::cout << "Missing NEWICK TREE file" << std::endl;
mvalle's avatar
mvalle committed
367
368
369
		// Falltrough

	case 1:
370
		std::cout << "Missing PHYLIP CODON ALIGNMENT file" << std::endl << std::endl;
371
372
		std::cout << "Usage:" << std::endl;
		std::cout << "    " << usage_msg << std::endl << std::endl;
mvalle's avatar
mvalle committed
373
		mCmdLineImpl->showHelp(parser_options);
374
		throw FastCodeMLFatal();
mvalle's avatar
mvalle committed
375
376
377
378
379
380

	default:
		mTreeFile = args.File(0);
		mGeneFile = args.File(1);
		break;
	}
381

mvalle's avatar
mvalle committed
382
383
	// Some final checks and settings
	if(!mGraphFile) mExportComputedTimes = UINT_MAX;
mvalle's avatar
mvalle committed
384
	if(mComputeHypothesis < 2) mInitH0fromH1 = false;
mvalle's avatar
mvalle committed
385
386
	if(mComputeHypothesis == 0 && mExportComputedTimes < 2) mExportComputedTimes = 0;
	if(mComputeHypothesis == 1 && mExportComputedTimes < 2) mExportComputedTimes = 1;
mvalle's avatar
mvalle committed
387
388
	if(mBranchStart == UINT_MAX && mBranchEnd < UINT_MAX) mBranchStart = 0;
	if(mBranchStart > mBranchEnd) throw FastCodeMLFatal("Start branch after end branch. Quitting.");
mvalle's avatar
mvalle committed
389
390
}