1 #------------------------------------------------------------------------------
2 # Copyright (C) 2007-2010 Richard Lincoln
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #------------------------------------------------------------------------------
17 """ Defines the entry point for Pylon.
20 #------------------------------------------------------------------------------
22 #------------------------------------------------------------------------------
29 from pylon
.io
import \
30 MATPOWERReader
, PSSEReader
, MATPOWERWriter
, ReSTWriter
, \
31 PickleReader
, PickleWriter
, PSSEWriter
33 from pylon
import DCPF
, NewtonPF
, FastDecoupledPF
, OPF
, UDOPF
35 #------------------------------------------------------------------------------
37 #------------------------------------------------------------------------------
39 logging
.basicConfig(stream
=sys
.stdout
, level
=logging
.DEBUG
,
40 format
="%(levelname)s: %(message)s")
42 logger
= logging
.getLogger("pylon")
44 #------------------------------------------------------------------------------
46 #------------------------------------------------------------------------------
48 def read_case(input, format
=None):
49 """ Returns a case object from the given input file object. The data
50 format may be optionally specified.
52 # Map of data file types to readers.
53 format_map
= {"matpower": MATPOWERReader
,
54 "psse": PSSEReader
, "pickle": PickleReader
}
57 if format_map
.has_key(format
):
58 reader_klass
= format_map
[format
]
59 reader
= reader_klass()
60 case
= reader
.read(input)
62 # Try each of the readers at random.
63 for reader_klass
in format_map
.values():
64 reader
= reader_klass()
66 case
= reader
.read(input)
76 #------------------------------------------------------------------------------
78 #------------------------------------------------------------------------------
80 def detect_data_file(input, file_name
=""):
81 """ Detects the format of a network data file according to the
82 file extension and the header.
84 _
, ext
= os
.path
.splitext(file_name
)
87 line
= input.readline() # first line
88 if line
.startswith("function"):
90 logger
.info("Recognised MATPOWER data file.")
91 elif line
.startswith("Bus.con" or line
.startswith("%")):
93 logger
.info("Recognised PSAT data file.")
96 input.seek(0) # reset buffer for parsing
98 elif (ext
== ".raw") or (ext
== ".psse"):
100 logger
.info("Recognised PSS/E data file.")
102 elif (ext
== ".pkl") or (ext
== ".pickle"):
104 logger
.info("Recognised pickled case.")
111 #------------------------------------------------------------------------------
113 #------------------------------------------------------------------------------
116 """ Parses the command line and call Pylon with the correct data.
118 parser
= optparse
.OptionParser(usage
="usage: pylon [options] input_file",
119 version
="%prog 0.4.4")
121 parser
.add_option("-o", "--output", dest
="output", metavar
="FILE",
122 help="Write the solution report to FILE.")
124 # parser.add_option("-q", "--quiet", action="store_true", dest="quiet",
125 # default=False, help="Print less information.")
127 parser
.add_option("-v", "--verbose", action
="store_true", dest
="verbose",
128 default
=False, help="Print more information.")
130 # parser.add_option("-g", "--gui", action="store_true", dest="gui",
131 # default=False, help="Use the portable graphical interface to Pylon.")
133 # parser.add_option("-n", "--no-report", action="store_true",
134 # dest="no_report", default=False, help="Suppress report output.")
136 parser
.add_option("-d", "--debug", action
="store_true", dest
="debug",
137 default
=False, help="Print debug information.")
139 parser
.add_option("-t", "--input-type", dest
="type", metavar
="TYPE",
140 default
="any", help="The argument following the -t is used to "
141 "indicate the format type of the input data file. The types which are "
142 "currently supported include: matpower, psse [default: %default]"
143 " If not specified Pylon will try to determine the type according to "
144 "the file name extension and the file header.")
146 parser
.add_option("-s", "--solver", dest
="solver", metavar
="SOLVER",
147 default
="acpf", help="The argument following the -s is used to"
148 "indicate the type of routine to use in solving. The types which are "
149 "currently supported are: 'dcpf', 'acpf', 'dcopf', 'acopf', 'udopf' "
150 "and 'none' [default: %default].")
152 parser
.add_option("-a", "--algorithm", action
="store_true",
153 metavar
="ALGORITHM", dest
="algorithm", default
="newton",
154 help="Indicates the algorithm type to be used for AC power flow. The "
155 "types which are currently supported are: 'newton' and 'fdpf' "
156 "[default: %default].")
158 parser
.add_option("-T", "--output-type", dest
="output_type",
159 metavar
="OUTPUT_TYPE", default
="rst", help="Indicates the output "
160 "format type. The type swhich are currently supported include: rst, "
161 "matpower, csv, excel and none [default: %default].")
163 (options
, args
) = parser
.parse_args()
166 logger
.setLevel(logging
.INFO
)
168 logger
.setLevel(logging
.DEBUG
)
170 logger
.setLevel(logging
.ERROR
)
173 outext
= {'psse': '.raw', 'matpower': '.m'}
175 if options
.output
== "-":
177 logger
.setLevel(logging
.CRITICAL
) # must stay quiet
178 # options.output_type = "none"
180 outfile
= open(options
.output
, "wb")
181 elif options
.output_type
is not None:
182 if options
.output_type
in outext
.keys():
183 inname
, ext
= os
.path
.splitext(args
[0])
184 outfile
= inname
+ outext
[options
.output_type
]
189 # if not options.no_report:
190 # logger.setLevel(logging.CRITICAL) # must stay quiet
196 elif (len(args
) == 0) or (args
[0] == "-"):
198 if sys
.stdin
.isatty():
199 # True if the file is connected to a tty device, and False
200 # otherwise (pipeline or file redirection).
204 # Handle piped input ($ cat ehv3.raw | pylon | rst2pdf -o ans.pdf).
208 infile
= open(filename
, "rb")
210 if options
.type == "any":
211 type = detect_data_file(infile
, filename
)
215 # Get the case from the input file-like object.
216 case
= read_case(infile
, type)
219 # Routine (and algorithm) selection.
220 if options
.solver
== "dcpf":
222 elif options
.solver
== "acpf":
223 if options
.algorithm
== "newton":
224 solver
= NewtonPF(case
)
225 elif options
.algorithm
== "fdpf":
226 solver
= FastDecoupledPF(case
)
228 logger
.critical("Invalid algorithm [%s]." % options
.algorithm
)
230 elif options
.solver
== "dcopf":
231 solver
= OPF(case
, True)
232 elif options
.solver
== "acopf":
233 solver
= OPF(case
, False)
234 elif options
.solver
== "udopf":
236 elif options
.solver
== "none":
239 logger
.critical("Invalid solver [%s]." % options
.solver
)
243 # Output writer selection.
244 if options
.output_type
== "matpower":
245 writer
= MATPOWERWriter(case
)
246 elif options
.output_type
== "psse":
247 writer
= PSSEWriter(case
)
248 elif options
.output_type
== "rst":
249 writer
= ReSTWriter(case
)
250 elif options
.output_type
== "csv":
251 from pylon
.io
.excel
import CSVWriter
252 writer
= CSVWriter(case
)
253 elif options
.output_type
== "excel":
254 from pylon
.io
.excel
import ExcelWriter
255 writer
= ExcelWriter(case
)
256 elif options
.output_type
== "pickle":
257 writer
= PickleWriter(case
)
259 logger
.critical("Invalid output type [%s]." % options
.output_type
)
262 if solver
is not None:
264 if options
.output_type
!= "none":
265 writer
.write(outfile
)
266 print('Output file {0} written'.format(outfile
))
268 logger
.critical("Unable to read case data.")
270 # Don't close stdin or stdout.
273 if options
.output
and not (options
.output
== "-"):
276 if __name__
== "__main__":
279 # EOF -------------------------------------------------------------------------