/* Copyright 2006 by Sean Luke and George Mason University Licensed under the Academic Free License version 3.0 See the file "LICENSE" for more information */ package sim.app.hexabugs; import sim.engine.*; import sim.field.grid.*; /** Hexa Non-toroidal Diffuser */ public /*strictfp*/ class HexaDiffuser implements Steppable { private static final long serialVersionUID = 1; DoubleGrid2D updateGrid; DoubleGrid2D tempGrid; double evaporationRate; double diffusionRate; public HexaDiffuser( final DoubleGrid2D updateGrid, final DoubleGrid2D tempGrid, final double evaporationRate, final double diffusionRate ) { this.updateGrid = updateGrid; this.tempGrid = tempGrid; this.evaporationRate = evaporationRate; this.diffusionRate = diffusionRate; } public void step(SimState state) { // Let's start with the easy stuff. We'll include some local variables because it's faster. // See heatbugs.Diffuser for more examples. // // locals are faster than instance variables // final DoubleGrid2D _valgrid = updateGrid; // final DoubleGrid2D v = valgrid; // shorter // final double[][] _valgrid_field = updateGrid.field; // final double[][] _valgrid2_field = tempGrid.field; // final int _gridWidth = _valgrid.getWidth(); // final int _gridHeight = _valgrid.getHeight(); // final double _evaporationRate = evaporationRate; // final double _diffusionRate = diffusionRate; // // double average; // DoubleBag temp = new DoubleBag(); // // for each x and y position // for(int x=0;x< _gridWidth;x++) // for(int y=0;y< _gridHeight;y++) // { // // Get neighbors // _valgrid.getMooreNeighbors(x,y,1,Grid2D.TOROIDAL,true,temp,null,null); // // //Go through neighbors and compute average // for( int i = 0 ; i < temp.numObjs ; i++ ) average += temp.objs[i]; // average /= (1+temp.numObjs); // // // load the new value into HexaBugs.this.valgrid2 // _valgrid2_field[x][y] = _evaporationRate * // (_valgrid_field[x][y] + _diffusionRate * // (average - _valgrid_field[x][y])); // } // The problem with this approach is that getMooreNeighbors is simple // and elegant but expensive. Instead we can simply hard-code it as so: // // locals are faster than instance variables // final DoubleGrid2D _valgrid = updateGrid; // final DoubleGrid2D v = valgrid; // shorter // final double[][] _valgrid_field = updateGrid.field; // final double[][] _valgrid2_field = tempGrid.field; // final int _gridWidth = _valgrid.getWidth(); // final int _gridHeight = _valgrid.getHeight(); // final double _evaporationRate = evaporationRate; // final double _diffusionRate = diffusionRate; // // double average; // // for each x and y position // for(int x=0;x< _gridWidth;x++) // for(int y=0;y< _gridHeight;y++) // { // average = // (_valgrid_field[x][y] + // _valgrid_field[v.stx(v.ulx(x,y))][v.sty(v.uly(x,y))] + // _valgrid_field[v.stx(v.urx(x,y))][v.sty(v.ury(x,y))] + // _valgrid_field[v.stx(v.dlx(x,y))][v.sty(v.dly(x,y))] + // _valgrid_field[v.stx(v.drx(x,y))][v.sty(v.dry(x,y))] + // _valgrid_field[v.stx(v.upx(x,y))][v.sty(v.upy(x,y))] + // _valgrid_field[v.stx(v.downx(x,y))][v.sty(v.downy(x,y))]) / 7.0; // // // load the new value into HexaBugs.this.valgrid2 // _valgrid2_field[x][y] = _evaporationRate * // (_valgrid_field[x][y] + _diffusionRate * // (average - _valgrid_field[x][y])); // } // Now we're getting somewhere speed-wise. But we can also eliminate the toroidal and hexagonal // cover functions with some work. Boy, it's a chore though. We include it here for fun, but // don't blame us if it's totally unreadable! // stolen from HeatBugs and modified for our own purposes // locals are faster than instance variables // locals are faster than instance variables final DoubleGrid2D _valgrid = updateGrid; final double[][] _valgrid_field = updateGrid.field; final double[][] _valgrid2_field = tempGrid.field; final int _gridWidth = _valgrid.getWidth(); final int _gridHeight = _valgrid.getHeight(); final double _evaporationRate = evaporationRate; final double _diffusionRate = diffusionRate; double average; double[] _past = _valgrid_field[_valgrid.stx(-1)]; double[] _current = _valgrid_field[0]; double[] _next; double[] _put; int yminus1; int yplus1; // for each x and y position for(int x=0;x< _gridWidth;x++) { int xplus1 = x+1; if( xplus1 == _gridWidth ) xplus1 = 0; _next = _valgrid_field[xplus1]; _put = _valgrid2_field[x]; boolean xmodulo2equals0 = x%2==0; yminus1 = _gridHeight-1; // initialized for(int y=0;y< _gridHeight;y++) { // for each neighbor of that position // go across top yplus1 = y+1; if( yplus1 == _gridHeight ) yplus1 = 0; if( xmodulo2equals0 ) { average = ( _current[y] + // CURRENT _past[yminus1] + //UL _next[yminus1] + // UR _past[y] + //DL _next[y] + // DR _current[yminus1] + // UP _current[yplus1] // DOWN ) / 7.0; } else { average = ( _current[y] + // CURRENT _past[y] + //UL _next[y] + // UR _past[yplus1] + //DL _next[yplus1] + // DR _current[yminus1] + // UP _current[yplus1] // DOWN ) / 7.0; } // load the new value into HeatBugs.this.valgrid2 _put[y] = _evaporationRate * (_current[y] + _diffusionRate * (average - _current[y])); // set y-1 to what y was "last time around" yminus1 = y; } // swap elements _past = _current; _current = _next; } updateGrid.setTo(tempGrid); } }