| 1 | within Modelica.Utilities; |
|---|
| 2 | package Examples |
|---|
| 3 | "Examples to demonstrate the usage of package Modelica.Utilities" |
|---|
| 4 | annotation (Documentation(info="<html> |
|---|
| 5 | <p> |
|---|
| 6 | This package contains quite involved examples that demonstrate how to |
|---|
| 7 | use the functions of package Modelica.Utilities. In particular |
|---|
| 8 | the 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> </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> </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> </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> |
|---|
| 41 | result = <b>calculator</b>(expression); |
|---|
| 42 | </pre></blockquote> |
|---|
| 43 | <h4>Description</h4> |
|---|
| 44 | <p> |
|---|
| 45 | This function demonstrates how a simple expression calculator |
|---|
| 46 | can be implemented in form of a recursive decent parser |
|---|
| 47 | using basically the Strings.scanToken(..) and Strings.scanDelimiter(..) |
|---|
| 48 | function. |
|---|
| 49 | </p> |
|---|
| 50 | <p> |
|---|
| 51 | The 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> |
|---|
| 102 | This function is nearly the same as Examples.<b>calculator</b>. |
|---|
| 103 | The essential difference is that function \"expression\" might be |
|---|
| 104 | used in other parsing operations: After the expression is |
|---|
| 105 | parsed and evaluated, the function returns with the value |
|---|
| 106 | of the expression as well as the position of the character |
|---|
| 107 | directly after the expression. |
|---|
| 108 | </p> |
|---|
| 109 | <p> |
|---|
| 110 | This function demonstrates how a simple expression calculator |
|---|
| 111 | can be implemented in form of a recursive decent parser |
|---|
| 112 | using basically the Strings.scanToken(..) and scanDelimiters(..) |
|---|
| 113 | function. There are 2 local functions (term, primary) that |
|---|
| 114 | implement the corresponding part of the grammar. |
|---|
| 115 | </p> |
|---|
| 116 | <p> |
|---|
| 117 | The 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> |
|---|
| 130 | The optional argument \"startIndex\" defines at which position |
|---|
| 131 | scanning of the expression starts. |
|---|
| 132 | </p> |
|---|
| 133 | <p> |
|---|
| 134 | In case of error, |
|---|
| 135 | the optional argument \"message\" is appended to the error |
|---|
| 136 | message, in order to give additional information where |
|---|
| 137 | the error occured. |
|---|
| 138 | </p> |
|---|
| 139 | <p> |
|---|
| 140 | This 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> |
|---|
| 157 | Note, in Examples.readRealParameter it is shown, how the expression |
|---|
| 158 | function 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> |
|---|
| 291 | result = <b>readRealParameter</b>(fileName, name); |
|---|
| 292 | </pre></blockquote> |
|---|
| 293 | <h4>Description</h4> |
|---|
| 294 | <p> |
|---|
| 295 | This function demonstrates how a function can be implemented |
|---|
| 296 | that reads the value of a parameter from file. The function |
|---|
| 297 | performs 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> |
|---|
| 313 | On file \"test.txt\" the following lines might be present: |
|---|
| 314 | </p> |
|---|
| 315 | <blockquote><pre> |
|---|
| 316 | // Motor data |
|---|
| 317 | J = 2.3 // inertia |
|---|
| 318 | w_rel0 = 1.5*2; // relative angular velocity |
|---|
| 319 | phi_rel0 = pi/3 |
|---|
| 320 | </pre></blockquote> |
|---|
| 321 | <p> |
|---|
| 322 | The function returns the value \"3.0\" when called as: |
|---|
| 323 | </p> |
|---|
| 324 | <blockquote><pre> |
|---|
| 325 | readRealParameter(\"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> |
|---|
| 394 | Model that shows the usage of Examples.readRealParameter and Examples.expression. |
|---|
| 395 | The model has 3 parameters and the values of these parameters are read |
|---|
| 396 | from a file. |
|---|
| 397 | </p> |
|---|
| 398 | </html>")); |
|---|
| 399 | end readRealParameterModel; |
|---|
| 400 | end Examples; |
|---|