1 | within ;
|
---|
2 | package KeyWordIO "Read and write data files with key words"
|
---|
3 | function writeRealVariable "Writing real variable to file"
|
---|
4 | input String fileName "Name of file" annotation(Dialog(__Dymola_loadSelector(filter = "Text files (*.txt; *.dat)", caption = "Open file in which Real parameters are present")));
|
---|
5 | input String name "Name of parameter";
|
---|
6 | input Real data "Actual value of parameter";
|
---|
7 | input Boolean append = false "Append data to file";
|
---|
8 | algorithm
|
---|
9 | if not append then
|
---|
10 | Modelica.Utilities.Files.removeFile(fileName);
|
---|
11 | end if;
|
---|
12 | Modelica.Utilities.Streams.print(name + " = " + String(data), fileName);
|
---|
13 | end writeRealVariable;
|
---|
14 |
|
---|
15 | function writeRealVariables "Write multiple real variables to file"
|
---|
16 | input String fileName "Name of file" annotation(Dialog(__Dymola_loadSelector(filter = "Text files (*.txt; *.dat)", caption = "Open file in which Real parameters are present")));
|
---|
17 | input String name[:] "Name of parameter";
|
---|
18 | input Real data[:] "Actual value of parameter";
|
---|
19 | input Boolean append = false "Append data to file";
|
---|
20 | algorithm
|
---|
21 | // Check sizes of name and data
|
---|
22 | if size(name, 1) <> size(data, 1) then
|
---|
23 | assert(false, "writeReadParameters: Lengths of name and data have to be equal");
|
---|
24 | end if;
|
---|
25 | // Write data to file
|
---|
26 | if not append then
|
---|
27 | Modelica.Utilities.Files.removeFile(fileName);
|
---|
28 | end if;
|
---|
29 | for k in 1:size(name, 1) loop
|
---|
30 | Modelica.Utilities.Streams.print(name[k] + " = " + String(data[k]), fileName);
|
---|
31 | end for;
|
---|
32 | end writeRealVariables;
|
---|
33 |
|
---|
34 | function readRealParameter "Read the value of a Real parameter from file"
|
---|
35 | import Modelica.Utilities.*;
|
---|
36 | input String fileName "Name of file" annotation(Dialog(__Dymola_loadSelector(filter = "Text files (*.txt; *.dat)", caption = "Open file in which Real parameters are present")));
|
---|
37 | input String name "Name of parameter";
|
---|
38 | input Boolean cache = false "Read file with/without caching";
|
---|
39 | output Real result "Actual value of parameter on file";
|
---|
40 | protected
|
---|
41 | String line;
|
---|
42 | String identifier;
|
---|
43 | String delimiter;
|
---|
44 | Integer nextIndex;
|
---|
45 | Integer iline = 1;
|
---|
46 | Types.TokenValue token;
|
---|
47 | String message = "in file \"" + fileName + "\" on line ";
|
---|
48 | String message2;
|
---|
49 | Boolean found = false;
|
---|
50 | Boolean endOfFile = false;
|
---|
51 | algorithm
|
---|
52 | if not cache then
|
---|
53 | (line, endOfFile) := readLineWithoutCache(fileName, iline);
|
---|
54 | else
|
---|
55 | (line, endOfFile) := Streams.readLine(fileName, iline);
|
---|
56 | end if;
|
---|
57 | while not found and not endOfFile loop
|
---|
58 | (token, nextIndex) := Strings.scanToken(line);
|
---|
59 | if token.tokenType == Types.TokenType.NoToken then
|
---|
60 | iline := iline + 1;
|
---|
61 | elseif token.tokenType == Types.TokenType.IdentifierToken then
|
---|
62 | if token.string == name then
|
---|
63 | message2 := message + String(iline);
|
---|
64 | (delimiter, nextIndex) := Strings.scanDelimiter(line, nextIndex, {"="}, message2);
|
---|
65 | (result, nextIndex) := expression(line, nextIndex, message2);
|
---|
66 | (delimiter, nextIndex) := Strings.scanDelimiter(line, nextIndex, {";", ""}, message2);
|
---|
67 | Strings.scanNoToken(line, nextIndex, message2);
|
---|
68 | found := true;
|
---|
69 | else
|
---|
70 | iline := iline + 1;
|
---|
71 | end if;
|
---|
72 | else
|
---|
73 | Strings.syntaxError(line, nextIndex, "Expected identifier " + message + String(iline));
|
---|
74 | end if;
|
---|
75 | if not cache then
|
---|
76 | (line, endOfFile) := readLineWithoutCache(fileName, iline);
|
---|
77 | else
|
---|
78 | (line, endOfFile) := Streams.readLine(fileName, iline);
|
---|
79 | end if;
|
---|
80 | end while;
|
---|
81 | // skip line
|
---|
82 | // name found, get value of "name = value;"
|
---|
83 | // wrong name, skip line
|
---|
84 | // wrong token
|
---|
85 | // read next line
|
---|
86 | /*
|
---|
87 | if not cache then
|
---|
88 | Streams.close(fileName);
|
---|
89 | end if;
|
---|
90 | */
|
---|
91 | if not found then
|
---|
92 | Streams.error("Parameter \"" + name + "\" not found in file \"" + fileName + "\"");
|
---|
93 | end if;
|
---|
94 | annotation(Documentation(info = "<html>
|
---|
95 | <h4>Syntax</h4>
|
---|
96 | <blockquote><pre>
|
---|
97 | result = <b>readRealParameter</b>(fileName, name);
|
---|
98 | </pre></blockquote>
|
---|
99 | <h4>Description</h4>
|
---|
100 | <p>
|
---|
101 | This function demonstrates how a function can be implemented
|
---|
102 | that reads the value of a parameter from file. The function
|
---|
103 | performs the following actions:
|
---|
104 | </p>
|
---|
105 | <ol>
|
---|
106 | <li> It opens file \"fileName\" and reads the lines of the file.</li>
|
---|
107 | <li> In every line, Modelica line comments (\"// ... end-of-line\")
|
---|
108 | are skipped </li>
|
---|
109 | <li> If a line consists of \"name = expression\" and the \"name\"
|
---|
110 | in this line is identical to the second argument \"name\"
|
---|
111 | of the function call, the expression calculator Examples.expression
|
---|
112 | is used to evaluate the expression after the \"=\" character.
|
---|
113 | The expression can optionally be terminated with a \";\".</li>
|
---|
114 | <li> The result of the expression evaluation is returned as
|
---|
115 | the value of the parameter \"name\". </li>
|
---|
116 | </ol>
|
---|
117 | <h4>Example</h4>
|
---|
118 | <p>
|
---|
119 | On file \"test.txt\" the following lines might be present:
|
---|
120 | </p>
|
---|
121 | <blockquote><pre>
|
---|
122 | // Motor data
|
---|
123 | J = 2.3 // inertia
|
---|
124 | w_rel0 = 1.5*2; // relative angular velocity
|
---|
125 | phi_rel0 = pi/3
|
---|
126 | </pre></blockquote>
|
---|
127 | <p>
|
---|
128 | The function returns the value \"3.0\" when called as:
|
---|
129 | </p>
|
---|
130 | <blockquote><pre>
|
---|
131 | readRealParameter(\"test.txt\", \"w_rel0\")
|
---|
132 | </pre></blockquote>
|
---|
133 | </html>"));
|
---|
134 | end readRealParameter;
|
---|
135 |
|
---|
136 | function expression "Expression interpreter that returns with the position after the expression (expression may consist of +,-,*,/,^,(),sin(), cos(), tan(), sqrt(), asin(), acos(), atan(), exp(), log(), pi"
|
---|
137 | import Modelica.Utilities.Types;
|
---|
138 | import Modelica.Utilities.Strings;
|
---|
139 | import Modelica.Math;
|
---|
140 | import Modelica.Constants;
|
---|
141 | input String string "Expression that is evaluated";
|
---|
142 | input Integer startIndex = 1 "Start scanning of expression at character startIndex";
|
---|
143 | input String message = "" "Message used in error message if scan is not successful";
|
---|
144 | output Real result "Value of expression";
|
---|
145 | output Integer nextIndex "Index after the scanned expression";
|
---|
146 | protected
|
---|
147 | function term "Evaluate term of an expression"
|
---|
148 | extends Modelica.Icons.Function;
|
---|
149 | input String string;
|
---|
150 | input Integer startIndex;
|
---|
151 | input String message = "";
|
---|
152 | output Real result;
|
---|
153 | output Integer nextIndex;
|
---|
154 | protected
|
---|
155 | Real result2;
|
---|
156 | Boolean scanning = true;
|
---|
157 | String opString;
|
---|
158 | algorithm
|
---|
159 | // scan for "primary * primary" or "primary / primary"
|
---|
160 | (result, nextIndex) := primary(string, startIndex, message);
|
---|
161 | while scanning loop
|
---|
162 | (opString, nextIndex) := Strings.scanDelimiter(string, nextIndex, {"*", "/", "^", ""}, message);
|
---|
163 | if opString == "" then
|
---|
164 | scanning := false;
|
---|
165 | else
|
---|
166 | (result2, nextIndex) := primary(string, nextIndex, message);
|
---|
167 | result := if opString == "*" then result * result2 else if opString == "/" then result / result2 else result ^ result2;
|
---|
168 | end if;
|
---|
169 | end while;
|
---|
170 | end term;
|
---|
171 |
|
---|
172 | function primary "Evaluate primary of an expression"
|
---|
173 | extends Modelica.Icons.Function;
|
---|
174 | input String string;
|
---|
175 | input Integer startIndex;
|
---|
176 | input String message = "";
|
---|
177 | output Real result;
|
---|
178 | output Integer nextIndex;
|
---|
179 | protected
|
---|
180 | Types.TokenValue token;
|
---|
181 | Real result2;
|
---|
182 | String delimiter;
|
---|
183 | String functionName;
|
---|
184 | Real pi = Constants.pi;
|
---|
185 | algorithm
|
---|
186 | (token, nextIndex) := Strings.scanToken(string, startIndex, unsigned= true);
|
---|
187 | if token.tokenType == Types.TokenType.DelimiterToken and token.string == "(" then
|
---|
188 | (result, nextIndex) := expression(string, nextIndex, message);
|
---|
189 | (delimiter, nextIndex) := Strings.scanDelimiter(string, nextIndex, {")"}, message);
|
---|
190 | elseif token.tokenType == Types.TokenType.RealToken then
|
---|
191 | result := token.real;
|
---|
192 | elseif token.tokenType == Types.TokenType.IntegerToken then
|
---|
193 | result := token.integer;
|
---|
194 | elseif token.tokenType == Types.TokenType.IdentifierToken then
|
---|
195 | if token.string == "pi" then
|
---|
196 | result := pi;
|
---|
197 | else
|
---|
198 | functionName := token.string;
|
---|
199 | (delimiter, nextIndex) := Strings.scanDelimiter(string, nextIndex, {"("}, message);
|
---|
200 | (result, nextIndex) := expression(string, nextIndex, message);
|
---|
201 | (delimiter, nextIndex) := Strings.scanDelimiter(string, nextIndex, {")"}, message);
|
---|
202 | if functionName == "sin" then
|
---|
203 | result := Math.sin(result);
|
---|
204 | elseif functionName == "cos" then
|
---|
205 | result := Math.cos(result);
|
---|
206 | elseif functionName == "tan" then
|
---|
207 | result := Math.tan(result);
|
---|
208 | elseif functionName == "sqrt" then
|
---|
209 | if result < 0.0 then
|
---|
210 | Strings.syntaxError(string, startIndex, "Argument of call \"sqrt(" + String(result) + ")\" is negative.\n" + "Imaginary numbers are not supported by the calculator.\n" + message);
|
---|
211 | end if;
|
---|
212 | result := sqrt(result);
|
---|
213 | elseif functionName == "asin" then
|
---|
214 | result := Math.asin(result);
|
---|
215 | elseif functionName == "acos" then
|
---|
216 | result := Math.acos(result);
|
---|
217 | elseif functionName == "atan" then
|
---|
218 | result := Math.atan(result);
|
---|
219 | elseif functionName == "exp" then
|
---|
220 | result := Math.exp(result);
|
---|
221 | elseif functionName == "log" then
|
---|
222 | if result <= 0.0 then
|
---|
223 | Strings.syntaxError(string, startIndex, "Argument of call \"log(" + String(result) + ")\" is negative.\n" + message);
|
---|
224 | end if;
|
---|
225 | result := log(result);
|
---|
226 | else
|
---|
227 | Strings.syntaxError(string, startIndex, "Function \"" + functionName + "\" is unknown (not supported)\n" + message);
|
---|
228 | end if;
|
---|
229 | end if;
|
---|
230 | else
|
---|
231 | Strings.syntaxError(string, startIndex, "Invalid primary of expression.\n" + message);
|
---|
232 | end if;
|
---|
233 | end primary;
|
---|
234 |
|
---|
235 | Real result2;
|
---|
236 | String signOfNumber;
|
---|
237 | Boolean scanning = true;
|
---|
238 | String opString;
|
---|
239 | algorithm
|
---|
240 | // scan for optional leading "+" or "-" sign
|
---|
241 | (signOfNumber, nextIndex) := Strings.scanDelimiter(string, startIndex, {"+", "-", ""}, message);
|
---|
242 | // scan for "term + term" or "term - term"
|
---|
243 | (result, nextIndex) := term(string, nextIndex, message);
|
---|
244 | if signOfNumber == "-" then
|
---|
245 | result := -result;
|
---|
246 | end if;
|
---|
247 | while scanning loop
|
---|
248 | (opString, nextIndex) := Strings.scanDelimiter(string, nextIndex, {"+", "-", ""}, message);
|
---|
249 | if opString == "" then
|
---|
250 | scanning := false;
|
---|
251 | else
|
---|
252 | (result2, nextIndex) := term(string, nextIndex, message);
|
---|
253 | result := if opString == "+" then result + result2 else result - result2;
|
---|
254 | end if;
|
---|
255 | end while;
|
---|
256 | annotation(Documentation(info = "<html>
|
---|
257 | <h4>Syntax</h4>
|
---|
258 | <blockquote><pre>
|
---|
259 | result = <b>expression</b>(string);
|
---|
260 | (result, nextIndex) = <b>expression</b>(string, startIndex=1, message=\"\");
|
---|
261 | </pre></blockquote>
|
---|
262 | <h4>Description</h4>
|
---|
263 | <p>
|
---|
264 | This function is nearly the same as Examples.<b>calculator</b>.
|
---|
265 | The essential difference is that function \"expression\" might be
|
---|
266 | used in other parsing operations: After the expression is
|
---|
267 | parsed and evaluated, the function returns with the value
|
---|
268 | of the expression as well as the position of the character
|
---|
269 | directly after the expression.
|
---|
270 | </p>
|
---|
271 | <p>
|
---|
272 | This function demonstrates how a simple expression calculator
|
---|
273 | can be implemented in form of a recursive decent parser
|
---|
274 | using basically the Strings.scanToken(..) and scanDelimiters(..)
|
---|
275 | function. There are 2 local functions (term, primary) that
|
---|
276 | implement the corresponding part of the grammar.
|
---|
277 | </p>
|
---|
278 | <p>
|
---|
279 | The following operations are supported (pi=3.14.. is a predefined constant):
|
---|
280 | </p>
|
---|
281 | <pre>
|
---|
282 | +, -
|
---|
283 | *, /, ^
|
---|
284 | (expression)
|
---|
285 | sin(expression)
|
---|
286 | cos(expression)
|
---|
287 | tan(expression)
|
---|
288 | sqrt(expression)
|
---|
289 | asin(expression)
|
---|
290 | acos(expression)
|
---|
291 | atan(expression)
|
---|
292 | exp(expression)
|
---|
293 | log(expression)
|
---|
294 | pi
|
---|
295 | </pre>
|
---|
296 | <p>
|
---|
297 | The optional argument \"startIndex\" defines at which position
|
---|
298 | scanning of the expression starts.
|
---|
299 | </p>
|
---|
300 | <p>
|
---|
301 | In case of error,
|
---|
302 | the optional argument \"message\" is appended to the error
|
---|
303 | message, in order to give additional information where
|
---|
304 | the error occured.
|
---|
305 | </p>
|
---|
306 | <p>
|
---|
307 | This function parses the following grammaer
|
---|
308 | </p>
|
---|
309 | <pre>
|
---|
310 | expression: [ add_op ] term { add_op term }
|
---|
311 | add_op : \"+\" | \"-\"
|
---|
312 | term : primary { mul_op primary }
|
---|
313 | mul_op : \"*\" | \"/\" | \"^\"
|
---|
314 | primary : UNSIGNED_NUMBER
|
---|
315 | | pi
|
---|
316 | | ( expression )
|
---|
317 | | functionName( expression )
|
---|
318 | function : sin
|
---|
319 | | cos
|
---|
320 | | tan
|
---|
321 | | sqrt
|
---|
322 | | asin
|
---|
323 | | acos
|
---|
324 | | atan
|
---|
325 | | exp
|
---|
326 | | log
|
---|
327 | </pre>
|
---|
328 | <p>
|
---|
329 | Note, in Examples.readRealParameter it is shown, how the expression
|
---|
330 | function can be used as part of another scan operation.
|
---|
331 | </p>
|
---|
332 | <h4>Example</h4>
|
---|
333 | <blockquote><pre>
|
---|
334 | expression(\"2+3*(4-1)\"); // returns 11
|
---|
335 | expression(\"sin(pi/6)\"); // returns 0.5
|
---|
336 | </pre></blockquote>
|
---|
337 | </html>"));
|
---|
338 | end expression;
|
---|
339 |
|
---|
340 | function readLineWithoutCache "Reads a line of text from a file without cahing and returns it in a string"
|
---|
341 | input String fileName "Name of the file that shall be read" annotation(Dialog(__Dymola_loadSelector(filter = "Text files (*.txt; *.dat)", caption = "Open file in which Real parameters are present")));
|
---|
342 | input Integer lineNumber(min = 1) "Number of line to read";
|
---|
343 | output String string "Line of text";
|
---|
344 | output Boolean endOfFile "If true, end-of-file was reached when trying to read line";
|
---|
345 |
|
---|
346 | external "C" string= ReadLine(fileName, lineNumber, endOfFile);
|
---|
347 | annotation(Include = "
|
---|
348 | #ifndef ReadLine_C
|
---|
349 | #define ReadLine_C
|
---|
350 | # include <stdio.h>
|
---|
351 | # include <string.h>
|
---|
352 | extern void ModelicaFormatError(const char* string,...);
|
---|
353 | extern char* ModelicaAllocateString(size_t len);
|
---|
354 | #ifndef MAXLEN
|
---|
355 | #define MAXLEN 133
|
---|
356 | #endif
|
---|
357 | const char* ReadLine(const char *fileName, int lineNumber, int* endOfFile)
|
---|
358 | {
|
---|
359 | FILE* fp;
|
---|
360 | char c, strline[MAXLEN];
|
---|
361 | char* line;
|
---|
362 | int iLine;
|
---|
363 | size_t lineLen;
|
---|
364 | if ((fp=fopen(fileName,\"r\")) == NULL)
|
---|
365 | {
|
---|
366 | ModelicaFormatError(\"ReadLine: File %s not found!\\n\",fileName);
|
---|
367 | return \"\";
|
---|
368 | }
|
---|
369 | iLine=0;
|
---|
370 | while (++iLine <= lineNumber)
|
---|
371 | {
|
---|
372 | c=fgetc(fp);
|
---|
373 | lineLen=1;
|
---|
374 | while (c != '\\n' && c != '\\r' && c != EOF)
|
---|
375 | {
|
---|
376 | if (lineLen < MAXLEN)
|
---|
377 | {
|
---|
378 | strline[lineLen-1]=c;
|
---|
379 | c=fgetc(fp);
|
---|
380 | lineLen++;
|
---|
381 | }
|
---|
382 | else
|
---|
383 | {
|
---|
384 | fclose(fp);
|
---|
385 | ModelicaFormatError(\"ReadLine: Line %d of file %s truncated!\\n\",iLine,fileName);
|
---|
386 | return \"\";
|
---|
387 | }
|
---|
388 | }
|
---|
389 | if (c == EOF && iLine < lineNumber)
|
---|
390 | {
|
---|
391 | fclose(fp);
|
---|
392 | line=ModelicaAllocateString(0);
|
---|
393 | *endOfFile=1;
|
---|
394 | return line;
|
---|
395 | }
|
---|
396 | }
|
---|
397 | fclose(fp);
|
---|
398 | strline[lineLen-1]='\0';
|
---|
399 | line=ModelicaAllocateString(lineLen);
|
---|
400 | strcpy(line, strline);
|
---|
401 | *endOfFile=0;
|
---|
402 | return line;
|
---|
403 | }
|
---|
404 | #endif
|
---|
405 | ", Documentation(info = "<html>
|
---|
406 | <h4>Syntax</h4>
|
---|
407 | <blockquote><pre>
|
---|
408 | (string, endOfFile) = <b>readLine</b>(fileName, lineNumber)
|
---|
409 | </pre></blockquote>
|
---|
410 | <h4>Description</h4>
|
---|
411 | <p>
|
---|
412 | Function <b>readLine</b>(..) opens the given file, reads enough of the
|
---|
413 | content to get the requested line, and returns the line as a string.
|
---|
414 | Lines are separated by LF or CR-LF; the returned string does not
|
---|
415 | contain the line separator.
|
---|
416 | </p>
|
---|
417 | <p>
|
---|
418 | If lineNumber > countLines(fileName), an empty string is returned
|
---|
419 | and endOfFile=true. Otherwise endOfFile=false.
|
---|
420 | </p>
|
---|
421 | </html>"));
|
---|
422 | end readLineWithoutCache;
|
---|
423 |
|
---|
424 | annotation(uses(Modelica(version="3.2.2")));
|
---|
425 | end KeyWordIO;
|
---|