source: coopr.opt/trunk/coopr/opt/solver/shellcmd.py @ 2167

Last change on this file since 2167 was 2167, checked in by jwatson, 10 years ago

Added a _report_timing attribute to the base solver class. If true, it will print out presolve/solve/postsolve timing statistics. The derived shell-based solver will additionally report log and solution file read times.

File size: 7.7 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__all__ = ['SystemCallSolver']
12
13import sys
14import os
15from coopr.opt.base import *
16from coopr.opt.base.solver import *
17from coopr.opt.results import SolverStatus
18import tempfile
19
20import pyutilib.common
21import pyutilib.services
22import pyutilib.subprocess
23import pyutilib.plugin.core
24import pyutilib.misc
25
26import time
27
28class SystemCallSolver(OptSolver):
29    """ A generic command line solver """
30
31    def __init__(self, **kwds):
32        """ Constructor """
33        OptSolver.__init__(self, **kwds)
34        if 'keepFiles' in kwds:
35            self.keepFiles = kwds['keepFiles']
36        else:
37            self.keepFiles = False
38        self.soln_file=None
39        self.log_file=None
40        self._timelimit=None
41        self._timer=""
42
43    def available(self, exception_flag=True):
44        """ True if the solver is available """
45        if self._assert_available:
46            return True
47        if not OptSolver.available(self,exception_flag):
48            return False
49        ans=self.executable()
50        if ans is None:
51           if exception_flag:
52              if self.executable() is None:
53                 raise pyutilib.common.ApplicationError, "No executable found for solver `"+self.name+"'"
54              else:
55                 raise pyutilib.common.ApplicationError, "Bad path for application `PICO' used by solver "+self.name+"': "+self.executable()
56           return False
57        return True
58
59    def create_command_line(self,executable,problem_files):
60        """
61        Create the command line that is executed.
62        """
63        raise NotImplementedError       #pragma:nocover
64
65    def process_logfile(self):
66        """
67        Process the logfile for information about the optimization process.
68        """
69        return SolverResults()
70
71    def process_soln_file(self,results):
72        """
73        Process auxilliary data files generated by the optimizer (e.g. solution files)
74        """
75        return results
76
77    def _executable(self):
78        """
79        Returns the executable used by this solver.
80        """
81        raise NotImplementedError
82
83    def _presolve(self, *args, **kwds):
84        """
85        Peform presolves.
86        """
87        if 'keepFiles' in kwds:
88            self.keepFiles = kwds['keepFiles']
89            del kwds['keepFiles']
90        OptSolver._presolve(self, *args, **kwds)
91        #
92        # Verify that the input problem exists       
93        #
94        for filename in self._problem_files:
95            if not os.path.exists(filename):
96                raise ValueError, "Solver failed to locate input problem file="+filename
97        #
98        # Create command line
99        #
100        self._command = self.create_command_line(self.executable(),self._problem_files)
101        self.log_file=self._command.log_file
102        #
103        # The pre-cleanup is probably unncessary, but also not harmful.
104        #
105        if self.log_file is not None and os.path.exists(self.log_file):
106           os.remove(self.log_file)
107        if self.soln_file is not None and os.path.exists(self.soln_file):
108           os.remove(self.soln_file)
109
110           
111    def _apply_solver(self):
112        if pyutilib.services.registered_executable("timer"):
113            self._timer=pyutilib.services.registered_executable("timer").get_path()
114        #
115        # Execute the command
116        #
117        pyutilib.plugin.core.PluginGlobals.env("coopr.opt").log.debug("Running "+self._command.cmd)
118
119        # display the log/solver file names prior to execution. this is useful
120        # in case something crashes unexpectedly, which is not without precedent.
121        if self.keepFiles:
122           if self.log_file is not None:
123              print "Solver log file=" + self.log_file
124           if self.soln_file is not None:
125              print "Solver solution file=" + self.soln_file
126           if self._problem_files is not []:
127               print "Solver problem files=",self._problem_files
128
129        sys.stdout.flush()
130        [rc,log] = self._execute_command(self._command)
131        sys.stdout.flush()
132        self._status = pyutilib.misc.Bunch(rc=rc, log=log)
133
134    def _postsolve(self):
135
136        if self.log_file is not None:
137           OUTPUT=open(self.log_file,"w")
138           print >>OUTPUT, "Solver command line: "+self._command.cmd
139           print >>OUTPUT, ""
140           print >>OUTPUT, self._status.log
141           OUTPUT.close()
142
143        # JPW: The cleanup of the problem file probably shouldn't be here, but rather
144        #      in the base OptSolver class. That would require movement of the keepFiles
145        #      attribute and associated cleanup logic to the base class, which I didn't
146        #      feel like doing at this present time. the base class remove_files method
147        #      should clean up the problem file.           
148
149        if self.log_file is not None and not os.path.exists(self.log_file):
150           raise IOError, "File " + self.log_file + " not generated while executing "+self.path
151        results = None
152        if self._results_format is not None:
153           results = self.process_output(self._status.rc)
154           if not self.keepFiles:
155              pyutilib.services.TempfileManager.clear_tempfiles()
156              # in some cases, the solution filename is not generated via the temp-file mechanism,
157              # instead being automatically derived from the input lp/nl filename. so, we may
158              # have to clean it up manually.
159              if os.path.exists(self.soln_file):
160                 os.remove(self.soln_file)
161
162        return results
163
164    def _execute_command(self,command):
165        """
166        Execute the command
167        """
168        try:
169            [rc, log] = pyutilib.subprocess.run(command.cmd, timelimit=self._timelimit, env=command.env, tee=self.tee, shell=True)
170        except pyutilib.common.WindowsError, err:
171            raise pyutilib.common.ApplicationError, "Could not execute the command: "+command.cmd+"\tError message: "+str(err)
172        sys.stdout.flush()
173        return [rc,log]
174
175    def process_output(self,rc):
176        """
177        Process the output files.
178        """
179        start_time = time.time()
180        if self._results_format is None:
181           raise ValueError, "Results format is None"
182        results = self.process_logfile()
183        log_file_completion_time = time.time()
184        if self._report_timing is True:
185           print "Log file read time="+str(log_file_completion_time - start_time)+" seconds"
186        if self.results_reader is None:
187           self.process_soln_file(results)
188           soln_file_completion_time = time.time()
189           if self._report_timing is True:           
190              print "Solution file read time="+str(soln_file_completion_time - log_file_completion_time)+" seconds"           
191        else:
192           results = self.results_reader(self.results_file, res=results)
193           results_reader_completion_time = time.time()
194           print "Results reader time="+str(results_reader_completion_time - log_file_completion_time)+" seconds"                     
195        if rc != None:
196           results.solver.error_rc=rc
197           if rc != 0:
198              results.solver.status=SolverStatus.error
199        return results
200
201    def _default_results_format(self, prob_format):
202        """ Returns the default results format for different problem
203            formats.
204        """
205        return ResultsFormat.soln
206
207
Note: See TracBrowser for help on using the repository browser.