root/branches/maintenance/3.0/Modelica/Utilities/Examples.mo

Revision 1038, 13.8 kB (checked in by otter, 10 months ago)

Fixed non-standard annotations reported by Gerd
(mostly fillColor/fillPattern in "Line(...)", but also some Dymola specific annotations)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1within Modelica.Utilities;
2package Examples
3  "Examples to demonstrate the usage of package Modelica.Utilities"
4  annotation (Documentation(info="<html>
5<p>
6This package contains quite involved examples that demonstrate how to
7use the functions of package Modelica.Utilities. In particular
8the following examples are present.
9</p>
10<ul>
11<li> Function <a href=\"Modelica://Modelica.Utilities.Examples.calculator\">calculator</a>
12     is an interpreter to evaluate
13     expressions consisting of +,-,*,/,(),sin(), cos(), tan(), sqrt(), pi.
14     For example: calculator(\"1.5*sin(pi/6)\"); <br>&nbsp;</li>
15<li> Function <a href=\"Modelica://Modelica.Utilities.Examples.expression\">expression</a>
16     is the basic function used in \"calculator\" to evaluate an expression.
17     It is useful if the expression interpreter is used in a larger
18     scan operation (such as readRealParameter below).<br>&nbsp;</li>
19<li> Function <a href=\"Modelica://Modelica.Utilities.Examples.readRealParameter\">readRealParameter</a>
20     reads the value of a parameter
21     from file, given the file and the parameter name. The value
22     on file is interpreted with the Examples.expression function
23     and can therefore be an expression.<br>&nbsp;</li>
24<li> Model <a href=\"Modelica://Modelica.Utilities.Examples.readRealParameterModel\">readRealParameterModel</a>
25     is a test model to demonstrate the usage of \"readRealParameter\". The model
26     contains 3 parameters that are read from file \"Modelica.Utilities/data/Examples_readRealParameters.txt\".
27     </li>
28</ul>
29</html>"));
30
31  function calculator
32    "Interpreter to evaluate simple expressions consisting of +,-,*,/,(),sin(), cos(), tan(), sqrt(), pi"
33    import Modelica.Utilities.Strings.*;
34    extends Modelica.Icons.Function;
35    input String string "Expression that is evaluated";
36    output Real result "Value of expression";
37
38    annotation (Documentation(info="<html>
39<h4>Syntax</h4>
40<blockquote><pre>
41result = <b>calculator</b>(expression);
42</pre></blockquote>
43<h4>Description</h4>
44<p>
45This function demonstrates how a simple expression calculator
46can be implemented in form of a recursive decent parser
47using basically the Strings.scanToken(..) and Strings.scanDelimiter(..)
48function.
49</p>
50<p>
51The following operations are supported (pi=3.14.. is a predefined constant):
52</p>
53<pre>
54   +, -
55   *, /
56   (expression)
57   sin(expression)
58   cos(expression)
59   tan(expression)
60   sqrt(expression)
61   pi
62</pre>
63<h4>Example</h4>
64<blockquote><pre>
65  calculator(\"2+3*(4-1)\");  // returns 11
66  calculator(\"sin(pi/6)\");  // returns 0.5
67</pre></blockquote>
68</html>"));
69
70  protected
71    Integer nextIndex;
72  algorithm
73    (result,nextIndex) := expression(string, 1);
74    Strings.scanNoToken(string,nextIndex);
75
76  end calculator;
77
78  function expression
79    "Expression interpreter that returns with the position after the expression (expression may consist of +,-,*,/,(),sin(), cos(), tan(), sqrt(), pi"
80    import Modelica.Utilities.Types;
81    import Modelica.Utilities.Strings;
82    import Modelica.Math;
83    import Modelica.Constants;
84
85    extends Modelica.Icons.Function;
86    input String string "Expression that is evaluated";
87    input Integer startIndex=1
88      "Start scanning of expression at character startIndex";
89    input String message=""
90      "Message used in error message if scan is not successful";
91    output Real result "Value of expression";
92    output Integer nextIndex "Index after the scanned expression";
93
94    annotation (Documentation(info="<html>
95<h4>Syntax</h4>
96<blockquote><pre>
97             result = <b>expression</b>(string);
98(result, nextIndex) = <b>expression</b>(string, startIndex=1, message=\"\");
99</pre></blockquote>
100<h4>Description</h4>
101<p>
102This function is nearly the same as Examples.<b>calculator</b>.
103The essential difference is that function \"expression\" might be
104used in other parsing operations: After the expression is
105parsed and evaluated, the function returns with the value
106of the expression as well as the position of the character
107directly after the expression.
108</p>
109<p>
110This function demonstrates how a simple expression calculator
111can be implemented in form of a recursive decent parser
112using basically the Strings.scanToken(..) and scanDelimiters(..)
113function. There are 2 local functions (term, primary) that
114implement the corresponding part of the grammar.
115</p>
116<p>
117The following operations are supported (pi=3.14.. is a predefined constant):
118</p>
119<pre>
120   +, -
121   *, /
122   (expression)
123   sin(expression)
124   cos(expression)
125   tan(expression)
126   sqrt(expression)
127   pi
128</pre>
129<p>
130The optional argument \"startIndex\" defines at which position
131scanning of the expression starts.
132</p>
133<p>
134In case of error,
135the optional argument \"message\" is appended to the error
136message, in order to give additional information where
137the error occured.
138</p>
139<p>
140This function parses the following grammaer
141</p>
142<pre>
143  expression: [ add_op ] term { add_op term }
144  add_op    : \"+\" | \"-\"
145  term      : primary { mul_op primary }
146  mul_op    : \"*\" | \"/\"
147  primary   : UNSIGNED_NUMBER
148              | pi
149              | ( expression )
150              | functionName( expression )
151  function  :   sin
152              | cos
153              | tan
154              | sqrt
155</pre>
156<p>
157Note, in Examples.readRealParameter it is shown, how the expression
158function can be used as part of another scan operation.
159</p>
160<h4>Example</h4>
161<blockquote><pre>
162  expression(\"2+3*(4-1)\");  // returns 11
163  expression(\"sin(pi/6)\");  // returns 0.5
164</pre></blockquote>
165</html>"));
166
167  protected
168  function term "Evaluate term of an expression"
169    extends Modelica.Icons.Function;
170    input String string;
171    input Integer startIndex;
172    input String message="";
173    output Real result;
174    output Integer nextIndex;
175    protected
176    Real result2;
177    Boolean scanning=true;
178    String operator;
179  algorithm
180    // scan for "primary * primary" or "primary / primary"
181    (result, nextIndex) := primary(string, startIndex, message);
182    while scanning loop
183      (operator, nextIndex) := Strings.scanDelimiter(
184                                      string, nextIndex, {"*","/",""}, message);
185      if operator == "" then
186         scanning := false;
187      else
188         (result2, nextIndex) := primary(string, nextIndex, message);
189         result := if operator == "*" then result*result2 else result/result2;
190      end if;
191    end while;
192  end term;
193
194  function primary "Evaluate primary of an expression"
195    extends Modelica.Icons.Function;
196
197    input String string;
198    input Integer startIndex;
199    input String message="";
200    output Real result;
201    output Integer nextIndex;
202    protected
203    Types.TokenValue token;
204    Real result2;
205    String delimiter;
206    String functionName;
207    Real pi = Constants.pi;
208  algorithm
209    (token,nextIndex) := Strings.scanToken(string, startIndex,unsigned=true);
210    if token.tokenType == Types.TokenType.DelimiterToken and token.string == "(" then
211      (result,nextIndex) := expression(string, nextIndex,message);
212      (delimiter,nextIndex) := Strings.scanDelimiter(string,nextIndex,{")"}, message);
213
214    elseif token.tokenType == Types.TokenType.RealToken then
215      result := token.real;
216
217    elseif token.tokenType == Types.TokenType.IntegerToken then
218      result := token.integer;
219
220    elseif token.tokenType == Types.TokenType.IdentifierToken then
221      if token.string == "pi" then
222         result := pi;
223      else
224         functionName := token.string;
225         (delimiter,nextIndex) := Strings.scanDelimiter(string,nextIndex,{"("}, message);
226         (result,nextIndex)    := expression(string, nextIndex, message);
227         (delimiter,nextIndex) := Strings.scanDelimiter(string,nextIndex,{")"}, message);
228         if functionName == "sin" then
229           result := Math.sin(result);
230         elseif functionName == "cos" then
231           result := Math.cos(result);
232         elseif functionName == "tan" then
233           result := Math.tan(result);
234         elseif functionName == "sqrt" then
235           if result < 0.0 then
236              Strings.syntaxError(string, startIndex, "Argument of call \"sqrt(" + String(result) + ")\" is negative.\n" +
237                          "Imaginary numbers are not supported by the calculator.\n" + message);
238           end if;
239           result := sqrt(result);
240         else
241           Strings.syntaxError(string, startIndex, "Function \"" + functionName + "\" is unknown (not supported)\n" +
242                                           message);
243         end if;
244      end if;
245
246    else
247      Strings.syntaxError(string, startIndex, "Invalid primary of expression.\n" + message);
248    end if;
249  end primary;
250
251    Real result2;
252    String signOfNumber;
253    Boolean scanning=true;
254    String operator;
255  algorithm
256    // scan for optional leading "+" or "-" sign
257    (signOfNumber, nextIndex) :=Strings.scanDelimiter(
258                                     string, startIndex, {"+","-",""}, message);
259
260    // scan for "term + term" or "term - term"
261    (result, nextIndex) := term(string, nextIndex, message);
262    if signOfNumber == "-" then
263       result := -result;
264    end if;
265
266    while scanning loop
267      (operator, nextIndex) := Strings.scanDelimiter(
268                                      string, nextIndex, {"+","-",""}, message);
269      if operator == "" then
270         scanning := false;
271      else
272         (result2, nextIndex) := term(string, nextIndex, message);
273         result := if operator == "+" then result+result2 else result-result2;
274      end if;
275    end while;
276
277  end expression;
278
279  function readRealParameter "Read the value of a Real parameter from file"
280    import Modelica.Utilities.*;
281    extends Modelica.Icons.Function;
282    input String fileName "Name of file"       annotation(Dialog(
283                           __Dymola_loadSelector(filter="Text files (*.txt)",
284                           caption="Open file in which Real parameters are present")));
285    input String name "Name of parameter";
286    output Real result "Actual value of parameter on file";
287
288    annotation (Documentation(info="<html>
289<h4>Syntax</h4>
290<blockquote><pre>
291result = <b>readRealParameter</b>(fileName, name);
292</pre></blockquote>
293<h4>Description</h4>
294<p>
295This function demonstrates how a function can be implemented
296that reads the value of a parameter from file. The function
297performs the following actions:
298</p>
299<ol>
300<li> It opens file \"fileName\" and reads the lines of the file.</li>
301<li> In every line, Modelica line comments (\"// ... end-of-line\")
302     are skipped </li>
303<li> If a line consists of \"name = expression\" and the \"name\"
304     in this line is identical to the second argument \"name\"
305     of the function call, the expression calculator Examples.expression
306     is used to evaluate the expression after the \"=\" character.
307     The expression can optionally be terminated with a \";\".</li>
308<li> The result of the expression evaluation is returned as
309     the value of the parameter \"name\". </li>
310</ol>
311<h4>Example</h4>
312<p>
313On file \"test.txt\" the following lines might be present:
314</p>
315<blockquote><pre>
316// Motor data
317J        = 2.3     // inertia
318w_rel0   = 1.5*2;  // relative angular velocity
319phi_rel0 = pi/3   
320</pre></blockquote>
321<p>
322The function returns the value \"3.0\" when called as:
323</p>
324<blockquote><pre>
325readRealParameter(\"test.txt\", \"w_rel0\")
326</pre></blockquote>
327</html>"));
328
329  protected
330    String line;
331    String identifier;
332    String delimiter;
333    Integer nextIndex;
334    Integer iline=1;
335    Types.TokenValue token;
336    String message = "in file \"" + fileName + "\" on line ";
337    String message2;
338    Boolean found = false;
339    Boolean endOfFile=false;
340  algorithm
341   (line, endOfFile) :=Streams.readLine(fileName, iline);
342
343    while not found and not endOfFile loop
344      (token, nextIndex) := Strings.scanToken(line);
345       if token.tokenType == Types.TokenType.NoToken then
346          // skip line
347          iline := iline + 1;
348       elseif token.tokenType == Types.TokenType.IdentifierToken then
349          if token.string == name then
350             // name found, get value of "name = value;"
351             message2 := message + String(iline);
352             (delimiter,nextIndex) := Strings.scanDelimiter(line, nextIndex, {"="}, message2);
353             (result,nextIndex)    := Examples.expression(line, nextIndex, message2);
354             (delimiter,nextIndex) := Strings.scanDelimiter(line, nextIndex, {";", ""}, message2);
355             Strings.scanNoToken(line, nextIndex, message2);
356             found := true;
357          else
358             // wrong name, skip line
359             iline := iline + 1;
360          end if;
361       else
362          // wrong token
363          Strings.syntaxError(line, nextIndex, "Expected identifier " + message + String(iline));
364       end if;
365
366       // read next line
367       (line, endOfFile) :=Streams.readLine(fileName, iline);
368    end while;
369
370    if not found then
371       Streams.error("Parameter \"" + name + "\" not found in file \"" + fileName + "\"");
372    end if;
373
374  end readRealParameter;
375
376  model readRealParameterModel
377    "Demonstrate usage of Examples.readRealParameter/.expression"
378    import SI = Modelica.SIunits;
379    extends Modelica.Icons.Example;
380
381    parameter String file = "Modelica/Utilities/data/Examples_readRealParameters.txt"
382      "File on which data is present" 
383          annotation(Dialog(__Dymola_loadSelector(filter="Text files (*.txt)",
384                        caption="Open text file to read parameters of the form \"name = value\"")));
385    parameter SI.Inertia J =              readRealParameter(file, "J")
386      "Inertia";
387    parameter SI.Angle phi_rel0 =         readRealParameter(file, "phi_rel0")
388      "Relative angle";
389    parameter SI.AngularVelocity w_rel0 = readRealParameter(file, "w_rel0")
390      "Relative angular velocity";
391
392    annotation (Documentation(info="<html>
393<p>
394Model that shows the usage of Examples.readRealParameter and Examples.expression.
395The model has 3 parameters and the values of these parameters are read
396from a file.
397</p>
398</html>"));
399  end readRealParameterModel;
400end Examples;
Note: See TracBrowser for help on using the browser.