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

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

Updates to allow for proper handling of variable maps in cases where formats cannot handle fully qualified,
human-readable variable names. Many ripple effects, as problem writers now must return a variable map (or None,
if not applicable. CBC now properly handles and reads NL and SOL input/output combinations!

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