Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing features to test the power grids benchmark in MARCO #14

Open
4 tasks done
casella opened this issue May 21, 2024 · 9 comments
Open
4 tasks done

Missing features to test the power grids benchmark in MARCO #14

casella opened this issue May 21, 2024 · 9 comments

Comments

@casella
Copy link
Contributor

casella commented May 21, 2024

To my knowlege, these issues must be resolved

The IDA solver of MARCO has a known issue with the sum() reduction operator, which currently does not generate the right Jacobian for the solver. However, this operator is not used by the benchmark, so everything should be ready once the above-mentioned issues are resolved.

@mscuttari
Copy link
Member

After closer inspection, I realized that MARCO already supports start attributes of record attributes, as visible in this test.
The sum reduction operator is also supported using the IDA solver, as per #15.

@casella
Copy link
Contributor Author

casella commented Jun 17, 2024

The OO version has been there for a while already, see Benchmarks/PowerGrid/Modelica_OO 😅

@mscuttari
Copy link
Member

The output of OMC (v1.24.0-dev-148-gac439f6130-cmake) when processing the builder model seems quite broken.
For example, the command

omc -i=PowerGridOOModelBuilders.ModelBuilder_Ne_2 PowerGridOOModelBuilders.mo --baseModelica -d=nonfScalarize,mergeComponents,combineSubscripts,evaluateAllParameters,vectorizeBindings

leads to

package 'ModelBuilder_Ne_2'
  function 'Modelica.Utilities.Files.fullPathName' "Get full path name of file or directory name"
    input String 'name';
    output String 'fullName';
  external "C" 'fullName' = ModelicaInternal_fullPathName('name') annotation(Library = "ModelicaExternalC", LibraryDirectory = "modelica://Modelica/Resources/Library", Include = "#include \"ModelicaInternal.h\"", IncludeDirectory = "modelica://Modelica/Resources/C-Sources");
  end 'Modelica.Utilities.Files.fullPathName';

  function 'Modelica.Utilities.Files.remove' "Remove file or directory (ignore call, if it does not exist)"
    input String 'name';
    String 'fullName';
    'Modelica.Utilities.Types.FileType' 'fileType' = 'Modelica.Utilities.Internal.FileSystem.stat'('name');
  algorithm
    if 'fileType' == 'Modelica.Utilities.Types.FileType'.RegularFile or 'fileType' == 'Modelica.Utilities.Types.FileType'.SpecialFile then
      'Modelica.Utilities.Internal.FileSystem.removeFile'('name');
    elseif 'fileType' == 'Modelica.Utilities.Types.FileType'.Directory then
      'fullName' := 'Modelica.Utilities.Files.fullPathName'('name');
      'Modelica.Utilities.Files.remove.removeDirectory'('fullName');
    end if;
  end 'Modelica.Utilities.Files.remove';

  function 'Modelica.Utilities.Files.remove.removeDirectory' "Remove a directory, even if it is not empty"
    input String 'name';
    Integer 'lenName' = 'Modelica.Utilities.Strings.length'('name');
    String 'name2' = if 'Modelica.Utilities.Strings.substring'('name', 'lenName', 'lenName') == "/" then 'Modelica.Utilities.Strings.substring'('name', 'lenName' - 1, 'lenName' - 1) else 'name';
  algorithm
    'Modelica.Utilities.Files.remove.removeDirectoryContents'('Modelica.Utilities.Internal.FileSystem.readDirectory'('name2', 'Modelica.Utilities.Internal.FileSystem.getNumberOfFiles'('name2')), 'name2');
    'Modelica.Utilities.Internal.FileSystem.rmdir'('name2');
  end 'Modelica.Utilities.Files.remove.removeDirectory';

  function 'Modelica.Utilities.Files.remove.removeDirectoryContents'
    input String[:] 'fileNames';
    input String 'name2';
  algorithm
    for 'i' in 1:size('fileNames', 1) loop
      'Modelica.Utilities.Files.remove'('name2' + "/" + 'fileNames'['i']);
    end for;
  end 'Modelica.Utilities.Files.remove.removeDirectoryContents';

  function 'Modelica.Utilities.Internal.FileSystem.getNumberOfFiles' "Get number of files and directories in a directory (POSIX functions opendir, readdir, closedir)"
    input String 'directory';
    output Integer 'result';
  external "C" 'result' = ModelicaInternal_getNumberOfFiles('directory') annotation(Library = "ModelicaExternalC", LibraryDirectory = "modelica://Modelica/Resources/Library", Include = "#include \"ModelicaInternal.h\"", IncludeDirectory = "modelica://Modelica/Resources/C-Sources");
  end 'Modelica.Utilities.Internal.FileSystem.getNumberOfFiles';

  function 'Modelica.Utilities.Internal.FileSystem.readDirectory' "Read names of a directory (POSIX functions opendir, readdir, closedir)"
    input String 'directory';
    input Integer 'nNames';
    output String['nNames'] 'names';
  external "C" ModelicaInternal_readDirectory('directory', 'nNames', 'names') annotation(Library = "ModelicaExternalC", LibraryDirectory = "modelica://Modelica/Resources/Library", Include = "#include \"ModelicaInternal.h\"", IncludeDirectory = "modelica://Modelica/Resources/C-Sources");
  end 'Modelica.Utilities.Internal.FileSystem.readDirectory';

  function 'Modelica.Utilities.Internal.FileSystem.removeFile' "Remove existing file (C function 'remove')"
    input String 'fileName';
  external "C" ModelicaInternal_removeFile('fileName') annotation(Library = "ModelicaExternalC", LibraryDirectory = "modelica://Modelica/Resources/Library", Include = "#include \"ModelicaInternal.h\"", IncludeDirectory = "modelica://Modelica/Resources/C-Sources");
  end 'Modelica.Utilities.Internal.FileSystem.removeFile';

  function 'Modelica.Utilities.Internal.FileSystem.rmdir' "Remove empty directory (POSIX function 'rmdir')"
    input String 'directoryName';
  external "C" ModelicaInternal_rmdir('directoryName') annotation(Library = "ModelicaExternalC", LibraryDirectory = "modelica://Modelica/Resources/Library", Include = "#include \"ModelicaInternal.h\"", IncludeDirectory = "modelica://Modelica/Resources/C-Sources");
  end 'Modelica.Utilities.Internal.FileSystem.rmdir';

  function 'Modelica.Utilities.Internal.FileSystem.stat' "Inquire file information (POSIX function 'stat')"
    input String 'name';
    output 'Modelica.Utilities.Types.FileType' 'fileType';
  external "C" 'fileType' = ModelicaInternal_stat('name') annotation(Library = "ModelicaExternalC", LibraryDirectory = "modelica://Modelica/Resources/Library", Include = "#include \"ModelicaInternal.h\"", IncludeDirectory = "modelica://Modelica/Resources/C-Sources");
  end 'Modelica.Utilities.Internal.FileSystem.stat';

  function 'Modelica.Utilities.Strings.length' "Return length of string"
    input String 'string';
    output Integer 'result';
  external "C" 'result' = ModelicaStrings_length('string') annotation(Library = "ModelicaExternalC", LibraryDirectory = "modelica://Modelica/Resources/Library", Include = "#include \"ModelicaStrings.h\"", IncludeDirectory = "modelica://Modelica/Resources/C-Sources");
  end 'Modelica.Utilities.Strings.length';

  function 'Modelica.Utilities.Strings.substring' "Return a substring defined by start and end index"
    input String 'string';
    input Integer 'startIndex'(min = 1);
    input Integer 'endIndex'(min = 1);
    output String 'result';
  external "C" 'result' = ModelicaStrings_substring('string', 'startIndex', 'endIndex') annotation(Library = "ModelicaExternalC", LibraryDirectory = "modelica://Modelica/Resources/Library", Include = "#include \"ModelicaStrings.h\"", IncludeDirectory = "modelica://Modelica/Resources/C-Sources");
  end 'Modelica.Utilities.Strings.substring';

  function 'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'
    input String 'string' = "";
    input String 'fileName' = "";
  external "C" ModelicaInternal_print('string', 'fileName') annotation(Library = "ModelicaExternalC", LibraryDirectory = "modelica://PowerGridOOModelBuilders/Resources/Library", Include = "#include \"ModelicaInternal.h\"", IncludeDirectory = "modelica://Modelica/Resources/C-Sources");
  end 'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print';

  type 'Modelica.Utilities.Types.FileType' = enumeration(NoFile, RegularFile, Directory, SpecialFile);

  model 'ModelBuilder_Ne_2'
    parameter Integer 'Ne' = 2 "Number of even rows and columns of the grid";
    final parameter Integer 'N' = 4 "Number of even rows and columns of the grid";
    final parameter Integer 'Ng' = 2 "Number of generators on each row and column";
    String 'f' = "D:/Temp/GridModels/Grid_Ne_2.mo";
  algorithm
    when initial() then
      'Modelica.Utilities.Files.remove'('f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("model Grid_Ne_2", 'f');

      for 'i' in 1:4 loop
        for 'j' in 1:4 loop
          'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  PowerGridOO.Components.Bus bus_" + String('i', 0, true) + "_" + String('j', 0, true) + ";", 'f');
        end for;
      end for;

      for 'i' in 1:4 loop
        for 'j' in 1:2 loop
          'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  PowerGridOO.Components.Generator gen_" + String('i', 0, true) + "_" + String('j', 0, true) + ";", 'f');
        end for;
      end for;

      for 'i' in 1:4 loop
        for 'j' in 1:2 loop
          'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  PowerGridOO.Components.Load load_" + String('i', 0, true) + "_" + String('j', 0, true) + ";", 'f');
        end for;
      end for;

      for 'i' in 1:4 loop
        for 'j' in 1:3 loop
          'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  PowerGridOO.Components.Line line_h_" + String('i', 0, true) + "_" + String('j', 0, true) + ";", 'f');
        end for;
      end for;

      for 'i' in 1:3 loop
        for 'j' in 1:4 loop
          'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  PowerGridOO.Components.Line line_v_" + String('i', 0, true) + "_" + String('j', 0, true) + ";", 'f');
        end for;
      end for;

      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  output PowerGridOO.Types.ComplexPU v_out[4];", 'f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  output PowerGridOO.Types.PU omega_out[4];", 'f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("equation", 'f');

      for 'i' in 1:2:4 loop
        for 'j' in 1:2 loop
          'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  connect(gen_" + String('i', 0, true) + "_" + String('j', 0, true) + ".port, bus_" + String('i', 0, true) + "_" + String(2 * 'j' - 1, 0, true) + ".port);", 'f');
        end for;
      end for;

      for 'i' in 2:2:4 loop
        for 'j' in 1:2 loop
          'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  connect(gen_" + String('i', 0, true) + "_" + String('j', 0, true) + ".port, bus_" + String('i', 0, true) + "_" + String(2 * 'j', 0, true) + ".port);", 'f');
        end for;
      end for;

      for 'i' in 1:2:4 loop
        for 'j' in 1:2 loop
          'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  connect(load_" + String('i', 0, true) + "_" + String('j', 0, true) + ".port, bus_" + String('i', 0, true) + "_" + String(2 * 'j', 0, true) + ".port);", 'f');
        end for;
      end for;

      for 'i' in 2:2:4 loop
        for 'j' in 1:2 loop
          'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  connect(load_" + String('i', 0, true) + "_" + String('j', 0, true) + ".port, bus_" + String('i', 0, true) + "_" + String(2 * 'j' - 1, 0, true) + ".port);", 'f');
        end for;
      end for;

      for 'i' in 1:4 loop
        for 'j' in 1:3 loop
          'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  connect(line_h_" + String('i', 0, true) + "_" + String('j', 0, true) + ".portA, bus_" + String('i', 0, true) + "_" + String('j', 0, true) + ".port);", 'f');
          'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  connect(line_h_" + String('i', 0, true) + "_" + String('j', 0, true) + ".portB, bus_" + String('i', 0, true) + "_" + String('j' + 1, 0, true) + ".port);", 'f');
        end for;
      end for;

      for 'i' in 1:3 loop
        for 'j' in 1:4 loop
          'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  connect(line_v_" + String('i', 0, true) + "_" + String('j', 0, true) + ".portA, bus_" + String('i', 0, true) + "_" + String('j', 0, true) + ".port);", 'f');
          'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  connect(line_v_" + String('i', 0, true) + "_" + String('j', 0, true) + ".portB, bus_" + String('i' + 1, 0, true) + "_" + String('j', 0, true) + ".port);", 'f');
        end for;
      end for;

      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  v_out[1] = bus_1_1.port.v;", 'f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  v_out[2] = bus_1_4.port.v;", 'f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  v_out[3] = bus_4_1.port.v;", 'f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  v_out[4] = bus_4_4.port.v;", 'f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  omega_out[1] = gen_1_1.omega;", 'f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  omega_out[2] = gen_1_2.omega;", 'f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  omega_out[3] = gen_4_1.omega;", 'f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  omega_out[4] = gen_4_2.omega;", 'f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("  annotation(__OpenModelica_commandLineOptions = \"-d=execstat --daeMode --tearingMethod=minimalTearing\",", 'f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("             __OpenModelica_simulationFlags(nls=\"kinsol\", lv=\"LOG_STATS\", noEquidistantTimeGrid = \"()\"),", 'f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("             experiment(StopTime = 5, Tolerance = 1e-6));", 'f');
      'PowerGridOOModelBuilders.ModelBuilder_Ne_2.print'("end Grid_Ne_2;", 'f');
    end when;
  end 'ModelBuilder_Ne_2';
end 'ModelBuilder_Ne_2';

Maybe am I not understanding how to use it?

@casella
Copy link
Contributor Author

casella commented Jun 17, 2024

The idea is to run the ModelBuilder models in OMC to generate the source code of the tests, add them to the library, and then running them with MARCO. You can already run, e.g. PowerGridOO.Test.Grid_Ne_1 or PowerGridOO.Test.Grid_Ne_2.

But first, we need to sort out the flat Modelica output from OMC, there are still a couple of open issues.

Question: can MARCO handle operator records?

@casella
Copy link
Contributor Author

casella commented Jun 17, 2024

The issues in OpenModelica/OpenModelica#12490 should be resolved now, I'm building a new Windows nightly build to test them. This will require some changes in the flags, w.r.t. what we have now in OMC.md.

With a bit of luck everything should be ready for today's Modelica meeting.

@casella
Copy link
Contributor Author

casella commented Jun 17, 2024

Regarding OpenModelica/OpenModelica#11792, if MARCO can handle Complex operator records natively, everything should be now OK, otherwise we still need to do something on the OMC BaseModelica output front.

@mscuttari
Copy link
Member

mscuttari commented Jun 17, 2024

OMC may need further works. I tested Grid_Ne_1 and the dimensions of variables are wrong:

  model 'Grid_Ne_1'
    ...
    'PowerGridOO.Types.ComplexPU' '$Line1.portA.v'('re'(start = fill(1.0, 4))) "Voltage phasor in p.u.";
    ...

$Line1.portA.v is typed as a record but should be an array of records.

Reproducing command:
omc -i=PowerGridOO.Test.Grid_Ne_1 PowerGridOO.mo --baseModelica -d=nonfScalarize,mergeComponents,combineSubscripts,evaluateAllParameters,vectorizeBindings

@casella
Copy link
Contributor Author

casella commented Jun 17, 2024

Sure, we need those two commits to be merged in and probably also to change the magic incantations.

@casella
Copy link
Contributor Author

casella commented Jun 18, 2024

See OMC.md.

I tried the flat Grid_Ne_1.mo
model obtained with OMC and the latest flags, but I got some invalid C code, see OpenModelica/OpenModelica#12598. This may not be a problem for MARCO, maybe it's just an OMC glitch. I tried to run it in Dymola, it compiles correctly, but then the runtime complains it is singular, while it can run the original model without problems. I'll need to check if the equations are different, though it's a bit boring, since there are 84 equations in that model...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants