Opened 5 years ago

Last modified 4 years ago

#5677 closed enhancement

Do not scalarize trivial connection equations when using -nonfScalarize — at Initial Version

Reported by: Francesco Casella Owned by: Per Östlund
Priority: critical Milestone: 1.17.0
Component: New Instantiation Version:
Keywords: Cc: Adrian Pop, stefano.cherubin@…, massimo.fioravanti@…, federico.terraneo@…, alberto.leva@…, giovanni.agosta@…

Description

Once #5643 is fixed, the NF should dump all the scalarized connect equations even in case -nonfScalarize is set. This can be quite inefficient when large number of connect statements are used. Consider the following case:

connector HeatPort
  flow Power Q;
  Temperature T;
end HeatPort;

model Volume
  parameter ThermalConductance G;
  parameter ThermalCapacitance C;

  HeatPort top;
  HeatPort bottom;
  HeatPort left;
  HeatPort right;
  HeatPort front;
  HeatPort back;

  Temperature T;
equation
  C*der(T) = G*((top.T-T) + (bottom.T-T) +
                (left.T-T) + (right.T-T) +
                (front.T-T) + (back.T-T));
end Volume;

model Cube
  parameter Integer N = 100;
  parameter Integer M = 100;
  parameter Integer P = 100;
  Volume vol[N, M, P];
equation
  for i in 1:N-1 loop
    for j in 1:M loop
      for k in 1:P loop
        connect(vol[i,j,k].bottom, vol[i+1,j,k].top);
      end for;
    end for;
  end for;
  for i in 1:N loop
    for j in 1:M-1 loop
      for k in 1:P loop
        connect(vol[i,j,k].right, vol[i,j+1,k].left);
      end for;
    end for;
  end for;
  for i in 1:N loop
    for j in 1:M loop
      for k in 1:P-1 loop
        connect(vol[i,j,k].back, vol[i,j,k+1].front);
      end for;
    end for;
  end for;
end Cube;

The original Cube model has three connect statements inside for loops. If loops are unrolled, about 3 million scalarized connect statements are created, corresponding to about 6 million scalar equations. In addition, there are about 60000 unconnected connectors on the six outer faces of the cube, corresponding to about 60000 additional equations stating the flow variables Q of those connectors are zero. Handling all these equations in the backend would take a lot of time.

However, this model satisfies the following properties:

  • each one of the ports vol[i,j,k].bottom, vol[i+1,j,k].top) for i in 1:N-1, j in 1:M, k in 1:P only show up in one connect statement inside a nested for loop
  • each one of the ports vol[i,j,k].right, vol[i,j+1,k].left for i in 1:N, j in 1:M-1, k in 1:P shows only up once in one connect statement inside a nested for loop
  • each one of the ports (vol[i,j,k].back, vol[i,j,k+1].front for i in 1:N, j in 1:M, k in 1:P-1 shows only up once in one connect statement inside a nested for loop
  • the ports vol[N,:,:].bottom, vol[1,:,:].top), vol[:,M,:].right, vol[:,1,:].left, (vol[:,:,N].back, vol[i:,:,1].front do not show up in any connect statement of the model

Hence, in the first two cases, only connection sets with two connectors will show up, while in the third case, only connection sets with a single connector will show up. The corresponding equations for flow and effort variables can then be easily derived by processing the unexpanded connection statements inside the for loops, leading to:

model Cube
  parameter Integer N = 100;
  parameter Integer M = 100;
  parameter Integer P = 100;
  Volume vol[N, M, P];
equation
  for i in 1:N-1 loop
    for j in 1:M loop
      for k in 1:P loop
        // connect(vol[i,j,k].bottom, vol[i+1,j,k].top);
        vol[i,j,k].bottom.T = vol[i+1,j,k].top.T;
        vol[i,j,k].bottom.Q + vol[i+1,j,k].top.Q = 0;
      end for;
    end for;
  end for;
  for i in 1:N loop
    for j in 1:M-1 loop
      for k in 1:P loop
        // connect(vol[i,j,k].right, vol[i,j+1,k].left);
        vol[i,j,k].right.T = vol[i,j+1,k].left.T;
        vol[i,j,k].right.Q + vol[i,j+1,k].left.Q = 0;
      end for;
    end for;
  end for;
  for i in 1:N loop
    for j in 1:M loop
      for k in 1:P-1 loop
        // connect(vol[i,j,k].back, vol[i,j,k+1].front);
        vol[i,j,k].back.T = vol[i,j,k+1].front.T;
        vol[i,j,k].back.Q + vol[i,j,k+1].front.Q = 0;
      end for;
    end for;
  end for;
  vol[N,:,:].bottom.Q = zeros(M,P);
  vol[1,:,:].top.Q = zeros(M,P);
  vol[:,M,:].right.Q = zeros(N,P);
  vol[:,1,:].left.Q = zeros(N,P);
  vol[:,:,N].back.Q = zeros(N,M);
  vol[i:,:,1].front.Q = zeros(N,M);
end Cube;

which only contains 12 vector or for-loop equations instead of 6 millions.

Summarizing, from what I understand the NF could keep track of connect statements found inside loops as the Modelica model is progressively parsed, taking note of which ports actually show up in the connect statements either in the form of array connections or of for loop connections.

At the end of the parsing, all the connect statements involving ports that only show up once can be expanded into the corresponding flow and effort equations, while array equations corresponding to the trivial boundary conditions can be generated for those ports that do not show up anywhere.

The remaining connection sets involving more than two connectors could be handled by unrolling them fully to scalar equations. Since they are expected to be a modest number, particularly if compared to the main loops or arrays, this shouldn't cause any major impact on compile time.

@perost, @adrpo, what do you think?

Change History (0)

Note: See TracTickets for help on using tickets.