@Override
    public boolean load() {
        // Clean up data if needed.
        if (null != heightData) {
            unloadHeightMap();
        }

        heightData = new float[size * size];
        float[][] tempBuffer = new float[2][size * size];
        Random random = new Random(seed);

        // pre-compute the coefficients in the fluid equation
        coefA = (4 - (8 * waveSpeed * waveSpeed * timeStep * timeStep) / (nodeDistance * nodeDistance)) / (viscosity * timeStep + 2);
        coefB = (viscosity * timeStep - 2) / (viscosity * timeStep + 2);
        coefC = ((2 * waveSpeed * waveSpeed * timeStep * timeStep) / (nodeDistance * nodeDistance)) / (viscosity * timeStep + 2);

        // initialize the heightmaps to random values except for the edges
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                tempBuffer[0][j + i * size] = tempBuffer[1][j + i * size] = randomRange(random, minInitialHeight, maxInitialHeight);
            }
        }

        int curBuf = 0;
        int ind;

        float[] oldBuffer;
        float[] newBuffer;

        // Iterate over the heightmap, applying the fluid simulation equation.
        // Although it requires knowledge of the two previous timesteps, it only
        // accesses one pixel of the k-1 timestep, so using a simple trick we only
        // need to store the heightmap twice, not three times, and we can avoid
        // copying data every iteration.
        for (int i = 0; i < iterations; i++) {
            oldBuffer = tempBuffer[1 - curBuf];
            newBuffer = tempBuffer[curBuf];

            for (int y = 0; y < size; y++) {
                for (int x = 0; x < size; x++) {
                    ind = x + y * size;
                    float neighborsValue = 0;
                    int neighbors = 0;

                    if (x > 0) {
                        neighborsValue += newBuffer[ind - 1];
                        neighbors++;
                    }
                    if (x < size - 1) {
                        neighborsValue += newBuffer[ind + 1];
                        neighbors++;
                    }
                    if (y > 0) {
                        neighborsValue += newBuffer[ind - size];
                        neighbors++;
                    }
                    if (y < size - 1) {
                        neighborsValue += newBuffer[ind + size];
                        neighbors++;
                    }
                    if (neighbors != 4) {
                        neighborsValue *= 4 / neighbors;
                    }
                    oldBuffer[ind] = coefA * newBuffer[ind] + coefB
                            * oldBuffer[ind] + coefC * (neighborsValue);
                }
            }

            curBuf = 1 - curBuf;
        }

        // put the normalized heightmap into the range [0...255] and into the heightmap
        for (int y = 0; y < size; y++) {
            for (int x = 0; x < size; x++) {
                heightData[x + y * size] = tempBuffer[curBuf][x + y * size];
            }
        }
        normalizeTerrain(NORMALIZE_RANGE);

        logger.fine("Created Heightmap using fluid simulation");

        return true;
    }
Generates a heightmap using fluid simulation and the attributes set by
the constructor or the setters.
jme3-terrain/src/main/java/com/jme3/terrain/heightmap/FluidSimHeightMap.java