コード例 #1
0
        /// <summary>
        /// Creates a Linear Programming problem instance for creating divergence free flows using a tiling method.
        /// The instance is stored in <see cref="LpModel"/>.
        /// </summary>
        /// <param name="minXFlux">Minimum flux in X direction as an integer</param>
        /// <param name="maxXFlux">Maximum flux in X direction as an integer</param>
        /// <param name="minYFlux">Minimum flux in Y direction as an integer</param>
        /// <param name="maxYFlux">Maximum flux in Y direction as an integer</param>
        /// <param name="currentTileGrid"></param>
        public static void BuildInitialModel(int minXFlux, int maxXFlux, int minYFlux, int maxYFlux,
                                             TileGrid currentTileGrid, int?[, ][] boundaryConditions)
        {
            int gridDimension = currentTileGrid.Dimension;

            //Number of variables is 2*n*(n+1) for n x n - grid
            LpModel = lpsolve.make_lp(0, 2 * gridDimension * (gridDimension + 1));

            //We always have four variables in the constraint
            int[] tileEdges = new int[4];

            //Improves performance when adding rows to model
            lpsolve.set_add_rowmode(LpModel, 1);
            lpsolve.set_obj_fn(LpModel, new double[2 * gridDimension * (gridDimension + 1)]);

            //Add incompressibility constraint to all cells which don't already have a flowtile on them.
            for (int row = 0; row < gridDimension; row++)
            {
                for (int column = 0; column < gridDimension; column++)
                {
                    if (!currentTileGrid.HasTile(row, column))
                    {
                        tileEdges = TileEdgeIndices(row, column, gridDimension);
                        lpsolve.add_constraintex(LpModel, 4, new double[] { -1, -1, 1, 1 }, tileEdges,
                                                 lpsolve.lpsolve_constr_types.EQ, 0);
                    }
                }
            }

            //Add row mode has to be turned off before continuing with other operations, if not then program crashes.
            lpsolve.set_add_rowmode(LpModel, 0);
            bool[] edgeSetFlag = new bool[2 * gridDimension * (gridDimension + 1) + 1];

            //Iterate over all rows and columns in the grid and set bounds on variables.
            for (int row = 0; row < gridDimension; row++)
            {
                for (int column = 0; column < gridDimension; column++)
                {
                    tileEdges = TileEdgeIndices(row, column, gridDimension);

                    if (!currentTileGrid.HasTile(row, column))
                    {
                        //Set the bounds for each edge flow. Zero if it is a boundary edge.
                        if (!edgeSetFlag[tileEdges[(int)Direction.Top]])
                        {
                            int?boundaryCondition = boundaryConditions[row, column][(int)Direction.Top];
                            if (boundaryCondition != null)
                            {
                                lpsolve.set_bounds(LpModel, tileEdges[(int)Direction.Top], (double)boundaryCondition, (double)boundaryCondition);
                                edgeSetFlag[tileEdges[(int)Direction.Top]] = true;
                            }
                            else
                            {
                                lpsolve.set_bounds(LpModel, tileEdges[(int)Direction.Top], minYFlux, maxYFlux);
                            }
                        }

                        if (!edgeSetFlag[tileEdges[(int)Direction.Right]])
                        {
                            int?boundaryCondition = boundaryConditions[row, column][(int)Direction.Right];
                            if (boundaryCondition != null)
                            {
                                lpsolve.set_bounds(LpModel, tileEdges[(int)Direction.Right], (double)boundaryCondition, (double)boundaryCondition);
                                edgeSetFlag[tileEdges[(int)Direction.Right]] = true;
                            }
                            else
                            {
                                lpsolve.set_bounds(LpModel, tileEdges[(int)Direction.Right], minXFlux, maxXFlux);
                            }
                        }

                        if (!edgeSetFlag[tileEdges[(int)Direction.Bottom]])
                        {
                            int?boundaryCondition = boundaryConditions[row, column][(int)Direction.Bottom];
                            if (boundaryCondition != null)
                            {
                                lpsolve.set_bounds(LpModel, tileEdges[(int)Direction.Bottom], (double)boundaryCondition, (double)boundaryCondition);
                                edgeSetFlag[tileEdges[(int)Direction.Bottom]] = true;
                            }
                            else
                            {
                                lpsolve.set_bounds(LpModel, tileEdges[(int)Direction.Bottom], minYFlux, maxYFlux);
                            }
                        }

                        if (!edgeSetFlag[tileEdges[(int)Direction.Left]])
                        {
                            int?boundaryCondition = boundaryConditions[row, column][(int)Direction.Left];
                            if (boundaryCondition != null)
                            {
                                lpsolve.set_bounds(LpModel, tileEdges[(int)Direction.Left], (double)boundaryCondition, (double)boundaryCondition);
                                edgeSetFlag[tileEdges[(int)Direction.Left]] = true;
                            }
                            else
                            {
                                lpsolve.set_bounds(LpModel, tileEdges[(int)Direction.Left], minXFlux, maxXFlux);
                            }
                        }
                    }
                    //Else there is a tile on the slot and the values are bounded by the flows from that tile
                    else
                    {
                        lpsolve.set_bounds(LpModel, tileEdges[(int)Direction.Top],
                                           currentTileGrid.GetFlowTile(row, column).Flux.TopEdge,
                                           currentTileGrid.GetFlowTile(row, column).Flux.TopEdge);

                        //Sets a flag that the edge flux has been set so that the value isn't overridden later.
                        edgeSetFlag[tileEdges[(int)Direction.Top]] = true;

                        lpsolve.set_bounds(LpModel, tileEdges[(int)Direction.Right],
                                           currentTileGrid.GetFlowTile(row, column).Flux.RightEdge,
                                           currentTileGrid.GetFlowTile(row, column).Flux.RightEdge);

                        //Sets a flag that the edge flux has been set so that the value isn't overridden later.
                        edgeSetFlag[tileEdges[(int)Direction.Right]] = true;

                        lpsolve.set_bounds(LpModel, tileEdges[(int)Direction.Bottom],
                                           currentTileGrid.GetFlowTile(row, column).Flux.BottomEdge,
                                           currentTileGrid.GetFlowTile(row, column).Flux.BottomEdge);

                        //Sets a flag that the edge flux has been set so that the value isn't overridden later.
                        edgeSetFlag[tileEdges[(int)Direction.Bottom]] = true;

                        lpsolve.set_bounds(LpModel, tileEdges[(int)Direction.Left],
                                           currentTileGrid.GetFlowTile(row, column).Flux.LeftEdge,
                                           currentTileGrid.GetFlowTile(row, column).Flux.LeftEdge);

                        //Sets a flag that the edge flux has been set so that the value isn't overridden later.
                        edgeSetFlag[tileEdges[(int)Direction.Left]] = true;
                    }
                }
            }

            lpsolve.set_verbose(LpModel, 0);
        }