source: coopr.pyomo/trunk/coopr/pyomo/scripting/pyomo.py @ 3679

Last change on this file since 3679 was 3679, checked in by wehart, 9 years ago

A major rework of command-line options that are supported for the
pyomo command. This now uses the argparse package, which is supported in
future Python releases.

  • Property svn:executable set to *
File size: 14.1 KB
Line 
1#  _________________________________________________________________________
2#
3#  Coopr: A COmmon Optimization Python Repository
4#  Copyright (c) 2008 Sandia Corporation.
5#  This software is distributed under the BSD License.
6#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
7#  the U.S. Government retains certain rights in this software.
8#  For more information, see the Coopr README.txt file.
9#  _________________________________________________________________________
10
11
12import argparse
13from coopr.opt.base import SolverFactory
14from coopr.opt.parallel import SolverManagerFactory
15from pyutilib.misc import Options, Container
16try:
17    import IPython
18    IPython_available=True
19    from IPython.Shell import IPShellEmbed
20    ipshell = IPShellEmbed([''],
21                banner = '\n# Dropping into Python interpreter',
22                exit_msg = '\n# Leaving Interpreter, back to Pyomo\n')
23except ImportError:
24    IPython_available=False
25
26try:
27   from pympler.muppy import muppy
28   from pympler.muppy import summary
29   from pympler.muppy import tracker
30   from pympler.asizeof import *   
31   pympler_available = True
32except ImportError:
33   pympler_available = False
34
35import util
36import gc
37
38
39def add_model_group(parser):
40    group = parser.add_argument_group('Model Options')
41
42    group.add_argument('--preprocess', '--load',
43        help='Specify a Python module that gets immediately executed (before '\
44             'the optimization model is setup).  If this option is specified '\
45             'multiple times, then the modules are executed in the specified '\
46             'order.',
47        action='append',
48        dest='preprocess',
49        default=[])
50    group.add_argument('--instance-only',
51        help='Generate a model instance, and then return',
52        action='store_true',
53        dest='only_instance',
54        default=False)
55    group.add_argument('--model-name',
56        help='The name of the model object that is created in the specified ' \
57             'Pyomo module',
58        action='store',
59        dest='model_name',
60        default='model')
61    group.add_argument('--model-options',
62        help='Options passed into a create_model() function to construct the '\
63             'model',
64        action='append',
65        dest='model_options',
66        default=[])
67    group.add_argument("--flatten-expressions", "--linearize-expressions",
68        help="EXPERIMENTAL: An option intended for use on linear or mixed-integer models " \
69             "in which expression trees in a model (constraints or objectives) are compacted " \
70             "into a more memory-efficient and concise form. The trees themselves are eliminated. ",
71        action="store_true",
72        dest="linearize_expressions",
73        default=False)
74    group.add_argument("--skip-canonical-repn",
75            help="Do not create the canonical representation. This is not necessary for solvers (e.g., ASL-based) that do not require it.",
76            action="store_true",
77            dest="skip_canonical_repn",
78            default=False)
79    group.add_argument('--save-model',
80        help='Specify the filename to which the model is saved.  The suffix ' \
81             'of this filename specifies the file format.  If debugging is '  \
82             "on, then this defaults to writing the file 'unknown.lp'.",
83        action='store',
84        dest='save_model',
85        default=None)
86
87
88def add_logging_group(parser):
89    group = parser.add_argument_group('Logging Options')
90
91    group.add_argument('-q','--quiet',
92        help='Disable all log messages except for those that refer to errors.', 
93        action='store_true',
94        dest='quiet',
95        default=False)
96    group.add_argument('-w','--warning',
97        help='Enable warning log messages for coopr and pyutilib.', 
98        action='store_true',
99        dest='warning',
100        default=False)
101    group.add_argument('-i','--info',
102        help='Enable informative log messages for coopr and pyutilib.', 
103        action='store_true',
104        dest='info',
105        default=False)
106    group.add_argument('-v','--verbose',
107        help="Indicate that debugging log messages should be printed.  This option can be specified multiple times to add log messages for other parts of coopr and pyutilib.",
108        action='count',
109        dest='verbose',
110        default=0)
111    group.add_argument('-d', '--debug',
112        help='This option indicates that debugging is performed.  This implies the verbose flag, but it also allows exceptions to trigger a failure in which the program stack is printed.',
113        action='store_true',
114        dest='debug',
115        default=False)
116
117
118def add_solver_group(parser):
119    solver_help=\
120        "This option specifies the type of solver that is used "\
121        "to solve the Pyomo model instance.  The following solver "\
122        "types are are currently supported:"
123    solver_list = SolverFactory.services()
124    solver_list = sorted( filter(lambda x: '_' != x[0], solver_list) )
125    solver_help += " %s." % ', '.join(solver_list)
126
127    parser.add_argument('--help-solvers',
128        help='Print information about the solvers that are available',
129        action='store_true',
130        dest='help_solvers',
131        default=False)
132
133    group = parser.add_argument_group('Solver Options')
134
135    group.add_argument('--solver',
136        help=solver_help,
137        action='store',
138        dest='solver',
139        #choices=solver_list,
140        default='glpk')
141    group.add_argument('--solver-manager',
142        help='Specify the technique that is used to manage solver executions.',
143        action='store',
144        dest='smanager_type',
145        #type='choice',
146        choices=SolverManagerFactory.services(),
147        default='serial')
148    group.add_argument('--solver-mipgap',
149        help='The solver termination mipgap',
150        action='store',
151        dest='solver_mipgap',
152        type=float,
153        default=None)
154    group.add_argument('--solver-options',
155        help='Options passed into the solver',
156        action='append',
157        dest='solver_options',
158        default=[])
159    group.add_argument('--solver-suffixes',
160        help='One or more solution suffixes to be extracted by the solver',
161        action='append',
162        dest='solver_suffixes',
163        default=[])
164    group.add_argument('--timelimit',
165        help='Limit to the number of seconds that the solver is run',
166        action='store',
167        dest='timelimit',
168        type=int,
169        default=0)
170
171def add_postsolve_group(parser):
172    group = parser.add_argument_group('Post-Solve Options')
173
174    group.add_argument('--postprocess',
175        help='Specify a Python module that gets executed after optimization. ' \
176             'If this option is specified multiple times, then the modules '  \
177             'are executed in the specified order.',
178        action='append',
179        dest='postprocess',
180        default=[])
181    group.add_argument('-l','--log',
182        help='Print the solver logfile after performing optimization',
183        action='store_true',
184        dest='log',
185        default=False)
186    group.add_argument('--logfile',
187        help='Redirect output to the specified logfile',
188        action='store',
189        dest='logfile',
190        default=None)
191    group.add_argument('--save-results',
192        help='Specify the filename to which the results are saved.',
193        action='store',
194        dest='save_results',
195        default=None)
196    group.add_argument('--stream-output',
197        help='Stream the solver output to provide information about the '     \
198             "solver's progress.",
199        action='store_true',
200        dest='tee',
201        default=False)
202    group.add_argument('-s','--summary',
203        help='Summarize the final solution after performing optimization',
204        action='store_true',
205        dest='summary',
206        default=False)
207
208def add_misc_group(parser):
209    parser.add_argument('--help-components',
210        help='Print information about modeling components supported by Pyomo',
211        action='store_true',
212        dest='help_components',
213        default=False)
214
215    group = parser.add_argument_group('Miscellaneous Options')
216
217    group.add_argument('--disable-gc',
218        help='Disable the garbage collecter',
219        action='store_true',
220        dest='disable_gc',
221        default=False)
222    group.add_argument('--interactive',
223        help='After executing Pyomo, launch an interactive Python shell.  If IPython is installed, this shell is an IPython shell.',
224        action='store_true',
225        dest='interactive',
226        default=False)
227    group.add_argument('-k','--keepfiles',
228        help='Keep temporary files',
229        action='store_true',
230        dest='keepfiles',
231        default=False)
232    group.add_argument('--path',
233        help='Give a path that is used to find the Pyomo python files',
234        action='store',
235        dest='path',
236        default='.')
237    group.add_argument('--profile',
238        help='Enable profiling of Python code.  The value of this option is ' \
239             'the number of functions that are summarized.',
240        action='store',
241        dest='profile',
242        type=int,
243        default=0)
244    if pympler_available is True:
245       group.add_argument("--profile-memory",
246                            help="If Pympler is available, report memory usage statistics for the generated instance and any associated processing steps. A value of 0 indicates disabled. A value of 1 forces summary memory statistics after major stages of the pyomo script. A value of 2 forces detailed memory statistics during instance creation and various steps of preprocessing. Values equal to 3 and higher currently provide no additional information. Higher values automatically enable all functionality associated with lower values, e.g., 2 turns on detailed and summary statistics.",
247                            action="store",
248                            dest="profile_memory",
249                            type=int,
250                            default=0)
251
252    group.add_argument('--tempdir',
253        help='Specify the directory where temporary files are generated',
254        action='store',
255        dest='tempdir',
256        default=None)
257   
258
259def create_parser():
260    #
261    #
262    # Setup command-line options
263    #
264    #
265    parser = argparse.ArgumentParser(
266                usage = '%(prog)s [options] <model.py> [<model.dat>]'
267                )
268    add_model_group(parser)
269    add_solver_group(parser)
270    add_postsolve_group(parser)
271    add_logging_group(parser)
272    add_misc_group(parser)
273    parser.add_argument('model_file', action='store', nargs='?', default='', help='A Python module that defines a Pyomo model')
274    parser.add_argument('data_files', action='store', nargs='*', default=[], help='Pyomo data files that defined data used to create a model instance')
275    return parser
276
277
278def run_pyomo(options=Options(), parser=None):
279
280    if (pympler_available is True) and (options.profile_memory >= 1):
281       memory_tracker = tracker.SummaryTracker()
282
283    if options.help_components:
284        util.print_components(options)
285        return Container()
286    if options.help_solvers:
287        util.print_solver_help(options)
288        return Container()
289    if not util.setup_environment(options):
290        return Container()                                   #pragma:nocover
291    if not util.apply_preprocessing(options, parser):
292        return Container()                                   #pragma:nocover
293    if (pympler_available is True) and (options.profile_memory >= 1): 
294       objects_before_instance_creation = muppy.get_objects()
295       summary_before_instance_creation = summary.summarize(objects_before_instance_creation)
296       print "Initial set of objects:"
297       summary.print_(summary_before_instance_creation, limit=50)                   
298       
299    model_data = util.create_model(options)
300   
301    if (pympler_available is True) and (options.profile_memory >= 1):
302       objects_after_instance_creation = muppy.get_objects()
303       summary_after_instance_creation = summary.summarize(objects_after_instance_creation)
304       print "Objects created during Pyomo instance creation:"       
305       memory_tracker.print_diff(summary1=summary_before_instance_creation, summary2=summary_after_instance_creation)
306   
307    if options.save_model or options.only_instance:
308        return Container(instance=model_data.instance)
309   
310    results, opt = util.apply_optimizer(options, model_data.instance)
311
312    if (pympler_available is True) and (options.profile_memory >= 1):
313       objects_after_optimization = muppy.get_objects()
314       summary_after_optimization = summary.summarize(objects_after_optimization)
315       print "Objects created during optimization:"
316       memory_tracker.print_diff(summary1=summary_after_instance_creation, summary2=summary_after_optimization)
317   
318    if not util.process_results(options, model_data.instance, results, opt):
319        return Container(instance=model_data.instance, results=results) #pragma:nocover
320
321    if (pympler_available is True) and (options.profile_memory >= 1):
322       objects_after_results_processing = muppy.get_objects()
323       summary_after_results_processing = summary.summarize(objects_after_results_processing)
324       diff_summary = summary.get_diff(summary_after_optimization, summary_after_results_processing)
325       print "Objects created during results processing:"
326       memory_tracker.print_diff(summary1=summary_after_optimization, summary2=summary_after_results_processing)
327   
328    util.apply_postprocessing(options, model_data.instance, results)
329
330    if (pympler_available is True) and (options.profile_memory >= 1):
331       final_objects = muppy.get_objects()
332       summary_final = summary.summarize(final_objects)
333       final_summary = summary.summarize(final_objects)
334       print "Final set of objects:"
335       summary.print_(final_summary, limit=50)
336   
337    model=model_data.model
338    instance=model_data.instance
339    if options.interactive:
340        if IPython_available:
341            ipshell()
342        else:
343            import code
344            shell = code.InteractiveConsole(locals())
345            print '\n# Dropping into Python interpreter'
346            shell.interact()
347            print '\n# Leaving Interpreter, back to Pyomo\n'
348           
349    return Container(instance=model_data.instance, results=results)
350
351
352def run(args=None):
353    result = util.run_command(run_pyomo, create_parser(), args=args, name='pyomo')
354    return result
355
Note: See TracBrowser for help on using the repository browser.