MASA-Core
AbstractBlockAligner.cpp
Go to the documentation of this file.
00001 /*******************************************************************************
00002  *
00003  * Copyright (c) 2010-2015   Edans Sandes
00004  *
00005  * This file is part of MASA-Core.
00006  * 
00007  * MASA-Core is free software: you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation, either version 3 of the License, or
00010  * (at your option) any later version.
00011  * 
00012  * MASA-Core is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with MASA-Core.  If not, see <http://www.gnu.org/licenses/>.
00019  *
00020  ******************************************************************************/
00021 
00022 #include "AbstractBlockAligner.hpp"
00023 
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <unistd.h>
00027 
00028 #include "config.h"
00029 #include "../processors/CPUBlockProcessor.hpp"
00030 
00031 /**
00032  * Set to (1) in order to print debug information in the stdout. This
00033  * significantly degrades the performance.
00034  */
00035 #define DEBUG (0)
00036 
00037 /*
00038  * The score constants
00039  */
00040 #define DNA_MATCH       (1)
00041 #define DNA_MISMATCH    (-3)
00042 #define DNA_GAP_EXT     (2)
00043 #define DNA_GAP_OPEN    (3)
00044 #define DNA_GAP_FIRST   (DNA_GAP_EXT+DNA_GAP_OPEN)
00045 
00046 
00047 #ifdef ENABLE_PROFILING
00048 #include "../libs/masa-core/src/common/Timer.hpp"
00049 static FILE* bitmap = NULL;
00050 #define PROFILING_INIT(name) bitmap = fopen(name, "wt");
00051 #define PROFILING_TIME(var) float var = Timer::getGlobalTime();
00052 #define PROFILING_PRINT(bx, by, score, done, time) fprintf(bitmap, "%d %d %d %d %d %p\n", by, bx, score, done, (int)((time)*1000), pthread_self());
00053 #else
00054 #define PROFILING_INIT
00055 #define PROFILING_TIME(var)
00056 #define PROFILING_PRINT(bx, by, score, done, time)
00057 #endif
00058 
00059 /**
00060  * Maximum recommended block size for better performance
00061  */
00062 #define RECOMMENDED_BLOCK_SIZE  (1024)
00063 
00064 /**
00065  * Minimum recommended grid size for better performance
00066  */
00067 #define RECOMMENDED_GRID_SIZE   (8)
00068 
00069 
00070 /**
00071  * AbstractBlockAligner Constructor.
00072  */
00073 AbstractBlockAligner::AbstractBlockAligner(AbstractBlockProcessor* blockProcessor, BlockAlignerParameters* params) {
00074         /*
00075          * Initializations
00076          */
00077         col = NULL;
00078         row = NULL;
00079 
00080         /*
00081          *  defines the constant parameters to be returned in the
00082          *  getScoreParameters() method
00083          */
00084         score_params.match = DNA_MATCH;
00085         score_params.mismatch = DNA_MISMATCH;
00086         score_params.gap_open = DNA_GAP_OPEN;
00087         score_params.gap_ext = DNA_GAP_EXT;
00088 
00089         /*
00090          * creates the custom parameters
00091          */
00092         if (params == NULL) {
00093                 this->params = new BlockAlignerParameters();
00094         } else {
00095                 this->params = params;
00096         }
00097         if (blockProcessor == NULL) {
00098                 this->blockProcessor = new CPUBlockProcessor();
00099         } else {
00100                 this->blockProcessor = blockProcessor;
00101         }
00102         this->blockPruner = new BlockPruningGenericN2();
00103 
00104         /*
00105          * Must be called to enable --fork parameter. This will allow
00106          * 2 process for each CPU. Each process will receive the same
00107          * workload.
00108          */
00109         int numCPU = sysconf( _SC_NPROCESSORS_ONLN );
00110         setForkCount(numCPU*2);
00111 
00112         preferredBlockSize = RECOMMENDED_BLOCK_SIZE;
00113         preferredGridSize = RECOMMENDED_GRID_SIZE;
00114 }
00115 
00116 /**
00117  * AbstractBlockAligner destructor.
00118  */
00119 AbstractBlockAligner::~AbstractBlockAligner() {
00120 }
00121 
00122 /*
00123  * This method defines which capabilities are implemented by this aligner.
00124  * The dispatch_special_column and variable_penalties capabilities are
00125  * not used yet by the MASA framework. The block_pruning and dispatch_last_cell
00126  * capabilities are not supported yet by this example aligner.
00127  */
00128 aligner_capabilities_t AbstractBlockAligner::getCapabilities() {
00129         aligner_capabilities_t capabilities;
00130 
00131         /* This is the supported capabilities of this Aligner subclass */
00132         capabilities.smith_waterman                     = SUPPORTED;
00133         capabilities.needleman_wunsch                   = SUPPORTED;
00134         capabilities.block_pruning                              = SUPPORTED;
00135         capabilities.customize_first_column     = SUPPORTED;
00136         capabilities.customize_first_row                = SUPPORTED;
00137         capabilities.dispatch_last_cell                 = NOT_SUPPORTED;
00138         capabilities.dispatch_last_column               = SUPPORTED;
00139         capabilities.dispatch_last_row                  = SUPPORTED;
00140         capabilities.dispatch_special_column    = SUPPORTED;
00141         capabilities.dispatch_special_row               = SUPPORTED;
00142         capabilities.dispatch_block_scores              = SUPPORTED;
00143         capabilities.dispatch_scores                    = SUPPORTED;
00144         capabilities.process_partition                  = SUPPORTED;
00145         capabilities.variable_penalties                 = NOT_SUPPORTED;
00146         capabilities.fork_processes                             = SUPPORTED;
00147 
00148         capabilities.maximum_seq0_len   = 0;
00149         capabilities.maximum_seq1_len   = 0;
00150 
00151         return capabilities;
00152 }
00153 
00154 /*
00155  * Returns the constant match/mismatch/gaps scores.
00156  */
00157 const score_params_t* AbstractBlockAligner::getScoreParameters() {
00158         return &score_params;
00159 }
00160 
00161 /*
00162  * See MicParameters and AbstractAlignerParameters classes.
00163  */
00164 IAlignerParameters* AbstractBlockAligner::getParameters() {
00165         return this->params;
00166 }
00167 
00168 /*
00169  * Initializes some structures of the Aligner. This method
00170  * is called only once for each stage, and only the sequence data may be
00171  * obtained in this time. The parameters must also be used here.
00172  * The partition boundaries must only be used in the alignPartition() method.
00173  *
00174  * See the IAligner and AbstractAligner classes documentation.
00175  */
00176 void AbstractBlockAligner::initialize() {
00177 
00178 }
00179 
00180 /*
00181  * The finalize method is called once for each stage, right before
00182  * the printFinalStatistics. Here we must deallocate all the previously
00183  * allocated structure.
00184  *
00185  * See the IAligner and AbstractAligner classes documentation.
00186  */
00187 void AbstractBlockAligner::finalize() {
00188         if (getGrid() != NULL) {
00189                 deallocateStructures();
00190         }
00191 }
00192 
00193 
00194 /**
00195  * Configures the grid for the given partition.
00196  * @param partition partition to be aligned.
00197  */
00198 Grid* AbstractBlockAligner::configureGrid(Partition partition) {
00199         /* creates the grid */
00200         Grid* grid = this->createGrid(partition);
00201 
00202         grid->setMinBlockSize(MIN_BLOCK_SIZE, MIN_BLOCK_SIZE);
00203 
00204         /* Block/Grid height */
00205         if (params->getBlockHeight() > 0) {
00206                 grid->setBlockHeight(params->getBlockHeight());
00207         } else if (params->getGridHeight() > 0) {
00208                 grid->splitGridVertically(params->getGridHeight());
00209         } else {
00210                 // Automatic configuration
00211                 if (!mustDispatchLastColumn()) {
00212                         int height = preferredBlockSize;
00213                         if (grid->getHeight() / height < preferredGridSize) {
00214                                 height = grid->getHeight() / preferredGridSize;
00215                         }
00216                         grid->setBlockHeight(height);
00217                 } else {
00218                         grid->setBlockHeight(grid->getWidth()/preferredGridSize/2);
00219                 }
00220         }
00221 
00222         /* Block/Grid width */
00223         if (params->getBlockWidth() > 0) {
00224                 grid->setBlockWidth(params->getBlockWidth());
00225         } else if (params->getGridWidth() > 0) {
00226                 grid->splitGridHorizontally(params->getGridWidth());
00227         } else {
00228                 // Automatic configuration
00229                 if (!mustDispatchLastColumn()) {
00230                         int width = preferredBlockSize;
00231                         if (grid->getWidth() / width < preferredGridSize) {
00232                                 width = grid->getWidth() / preferredGridSize;
00233                         }
00234                         grid->setBlockWidth(width);
00235                 } else {
00236                         grid->splitGridHorizontally(preferredGridSize);
00237                 }
00238         }
00239 
00240         /* block statistics */
00241         int block_width  = grid->getBlockWidth(0,0);
00242         int block_height = grid->getBlockHeight(0,0);
00243         statMinBlockWidth  = std::min(statMinBlockWidth , block_width);
00244         statMinBlockHeight = std::min(statMinBlockHeight, block_height);
00245         statMaxBlockWidth  = std::max(statMaxBlockWidth , block_width);
00246         statMaxBlockHeight = std::max(statMaxBlockHeight, block_height);
00247 
00248         /* grid statistics */
00249         int grid_width = grid->getGridWidth();
00250         int grid_height = grid->getGridHeight();
00251         statMinGridWidth  = std::min(statMinGridWidth , grid_width);
00252         statMinGridHeight = std::min(statMinGridHeight, grid_height);
00253         statMaxGridWidth  = std::max(statMaxGridWidth , grid_width);
00254         statMaxGridHeight = std::max(statMaxGridHeight, grid_height);
00255 
00256         if (DEBUG) printf("Configured Grid: B: %d x %d    G: %d x %d\n", block_width, block_height, grid_width, grid_height);
00257         return grid;
00258 }
00259 
00260 
00261 void AbstractBlockAligner::setSequences(const char* seq0, const char* seq1, int seq0_len, int seq1_len) {
00262         blockProcessor->setSequences(seq0, seq1, seq0_len, seq1_len);
00263 }
00264 
00265 void AbstractBlockAligner::unsetSequences() {
00266         blockProcessor->unsetSequences();
00267 }
00268 
00269 /**
00270  * Aligns the given partition, processing it block by block using a customized
00271  * scheduler.
00272  *
00273  * @param partition partition to be aligned.
00274  * @see IAligner::alignPartition
00275  */
00276 void AbstractBlockAligner::alignPartition(Partition partition) {
00277         //fprintf(stderr, "alignPartition()\n");
00278         //createDispatcherQueue(); // Uncomment this if you want thread-safe calls
00279 
00280         /* configures the grid */
00281         Grid* grid = configureGrid(partition);
00282 
00283         /* the block pruning initialization must be done after grid configuration */
00284         initializeBlockPruning(blockPruner);
00285 
00286         /* allocates the memory structures. It must be called after grid configuration */
00287         allocateStructures();
00288 
00289         /* reads the first top-left cell of the partition. */
00290         cell_t dummy;
00291         receiveFirstColumn(&dummy, 1); // initializes the AbstractAligner::firstColumnTail
00292         receiveFirstRow(&dummy, 1); // initializes the AbstractAligner::firstRowTail
00293         // TODO assert if both tails are equal?
00294 
00295         /* statistics initializations */
00296         statTotalBlocks = 0;
00297         statPrunedBlocks = 0;
00298 
00299         static char str[500];
00300         sprintf(str, "profiling.%08d.%08d.%08d.%08d.%d.txt", partition.getI0(), partition.getJ0(), partition.getI1(), partition.getJ1(), mustDispatchLastColumn());
00301         PROFILING_INIT(str);
00302 
00303         /* local initializations */
00304         int grid_width = grid->getGridWidth();
00305         int grid_height = grid->getGridHeight();
00306         scheduleBlocks(grid_width, grid_height);
00307 
00308         // TODO o dispatch score deve ser feito on-the-fly durante o estagio 2,
00309         // caso contrario o processamento nao ira parar se encontrarmos o goal score.
00310         for (int bx = 0; bx < grid_width; bx++) {
00311                 for (int by = 0; by < grid_height; by++) {
00312                         /* Dispatch the best score found in block (bx,by) */
00313                         dispatchScore(grid_scores[bx][by], bx, by);
00314                 }
00315         }
00316 
00317         if (mustDispatchLastCell()) {
00318                 score_t score;
00319                 score.score = row[grid_width-1][grid->getBlockWidth(grid_width-1, grid_height-1)-1].h;
00320                 score.i = partition.getI1()-1;
00321                 score.j = partition.getJ1()-1;
00322                 dispatchScore(score, grid_width-1, grid_height-1);
00323         }
00324 
00325         deallocateStructures();
00326         //destroyDispatcherQueue(); // Uncomment this if you want thread-safe calls
00327 }
00328 
00329 
00330 /**
00331  * This method aligns block (bx,by). This method calls the
00332  * AbstractBlockAligner::alignBlock(int,int,int,int,int,int)
00333  * with additional information about block coordinates.
00334  *
00335  * @param bx horizontal coordinate of the block in the grid
00336  * @param by vertical coordinate of the block in the grid
00337  */
00338 void AbstractBlockAligner::alignBlock(int bx, int by) {
00339         int i0;
00340         int i1;
00341         int j0;
00342         int j1;
00343 
00344         /* obtains the boundaries of block (bx, by) */
00345         getGrid()->getBlockPosition(bx, by, &i0, &j0, &i1, &j1);
00346 
00347         alignBlock(bx, by, i0, j0, i1, j1);
00348 }
00349 
00350 /**
00351  * This method calls AbstractBlockProcessor::processBlock(int,int,int,int,int,int,int)
00352  * to execute the recurrence relation for a block.
00353  *
00354  * @param bx horizontal block coordinate
00355  * @param by vertical block coordinate
00356  * @param i0 vertical first row of the block
00357  * @param j0 horizontal first column of the block
00358  * @param i1 vertical last row of the block
00359  * @param j1 horizontal last column of the block
00360  * @param true if the block was processed or false if it was pruned.
00361  */
00362 bool AbstractBlockAligner::processBlock(int bx, int by, int i0, int j0, int i1, int j1) {
00363         if (!isBlockPruned(bx, by)) {
00364                 /* the block was not pruned */
00365                 if (DEBUG) printf(">>>AbstractBlockAligner::processBlock(%d, %d, %d, %d, %d, %d)\n", bx, by, i0, j0, i1, j1);
00366 
00367 
00368                 //if (!mustContinue()) return; // MASA-core is telling to stop
00369 
00370                 PROFILING_TIME(t0);
00371 
00372                 /* processes the block */
00373                 grid_scores[bx][by] = blockProcessor->processBlock(row[bx], col[by], i0, j0, i1, j1, getRecurrenceType());
00374 
00375                 PROFILING_TIME(t1);
00376                 PROFILING_PRINT(bx, by, grid_scores[bx][by].score, 1, t1-t0);
00377 
00378                 /* Updates the block pruning status */
00379                 pruningUpdate(bx, by, grid_scores[bx][by].score);
00380 
00381                 increaseBlockStat(false);
00382 
00383                 /* Dispatch the best score found in block (bx,by) */
00384                 //dispatchScore(grid_scores[bx][by], bx, by);
00385                 return true;
00386         } else {
00387                 /* the block was pruned */
00388                 ignoreBlock(bx, by);
00389                 return false;
00390         }
00391 
00392 }
00393 
00394 /*
00395  * Profiles this block as "pruned"
00396  */
00397 void AbstractBlockAligner::ignoreBlock(int bx, int by) {
00398         PROFILING_PRINT(bx, by, 0, 0, 0);
00399         increaseBlockStat(true);
00400 }
00401 
00402 /*
00403  * Updates statTotalBlocks and statPrunedBlocks variables
00404  */
00405 void AbstractBlockAligner::increaseBlockStat(const bool pruned) {
00406         statTotalBlocks++;
00407         if (pruned) {
00408                 statPrunedBlocks++;
00409         }
00410 }
00411 
00412 
00413 /**
00414  * Indicates if the blocks on row $by$ must dispatch its last row.
00415  *
00416  * @param by the row of blocks.
00417  * @return true if the last row of the block will be stored (special row).
00418  */
00419 bool AbstractBlockAligner::isSpecialRow(int by) {
00420         /*
00421          * Dispatch special rows with a minimum defined distance (getSpecialRowInterval()).
00422          */
00423         if (mustDispatchLastRow() && by == getGrid()->getGridHeight()-1) {
00424                 return true;
00425         } else if (mustDispatchSpecialRows()) {
00426                 /*
00427                  * Note that only the last rows of the blocks are suitable to be a
00428                  * special row.
00429                  */
00430                 const int block_height = getGrid()->getBlockHeight(0, 0); // considering that all the blocks has the same height
00431                 int flush_block_interval = (getSpecialRowInterval()+block_height-1)/block_height;
00432                 if (flush_block_interval <= 0) {
00433                         flush_block_interval = 1;
00434                 }
00435 
00436                 return ((by+1) % flush_block_interval == 0);
00437         } else {
00438                 return false;
00439         }
00440 }
00441 
00442 /**
00443  * Indicates if the blocks on column $bx$ must dispatch its last column.
00444  *
00445  * @param bx the column of blocks.
00446  * @return true if the last column of the block will be stored (special column).
00447  */
00448 bool AbstractBlockAligner::isSpecialColumn(int bx) {
00449         return (mustDispatchLastColumn() && bx == getGrid()->getGridWidth()-1);
00450 }
00451 
00452 /**
00453  * Prints the pruning statistics and grid used range.
00454  * @param file handler to print out the statistics.
00455  * @see IAligner::printStatistics
00456  */
00457 void AbstractBlockAligner::printStatistics(FILE* file) {
00458         // Print final statistics to the statistics file;
00459         fprintf(file, "\n=====  PRUNING STATS   =====\n");
00460         fprintf(file, "Pruned Blocks: %d\n", statPrunedBlocks);
00461         fprintf(file, "Pruned Blocks: %.4f%%\n",
00462                         (statPrunedBlocks * 100.0f) / statTotalBlocks);
00463 
00464         fprintf(file, "\n===== RUNTIME VARIABLES =====\n");
00465         fprintf(file, "      Block Width: %d-%d\n", statMinBlockWidth, statMaxBlockWidth);
00466         fprintf(file, "     Block Height: %d-%d\n", statMinBlockHeight, statMaxBlockHeight);
00467         fprintf(file, "       Grid Width: %d-%d\n", statMinGridWidth, statMaxGridWidth);
00468         fprintf(file, "      Grid Height: %d-%d\n", statMinGridHeight, statMaxGridHeight);
00469 
00470         fflush(file);
00471 }
00472 
00473 /**
00474  * Prints the runtime parameters.
00475  * @param file handler to print out the statistics.
00476  * @see IAligner::printInitialStatistics
00477  */
00478 void AbstractBlockAligner::printInitialStatistics(FILE* file) {
00479         fprintf(file, "\n===== RUNTIME PARAMETERS =====\n");
00480         fprintf(file, " %s height: %d\n",
00481                         params->getBlockHeight() ? "Block" : "Grid",
00482                         params->getBlockHeight() ? params->getBlockHeight() : params->getGridHeight());
00483         fprintf(file, " %s width: %d\n",
00484                         params->getBlockWidth() ? "Block" : "Grid",
00485                         params->getBlockWidth() ? params->getBlockWidth() : params->getGridWidth());
00486         fprintf(file, " ForkID: %d\n", params->getForkId());
00487 }
00488 
00489 /**
00490  * @copydoc IAligner::clearStatistics
00491  */
00492 void AbstractBlockAligner::clearStatistics() {
00493         statTotalBlocks = 0;
00494         statPrunedBlocks = 0;
00495 
00496         statMinBlockWidth = INF;
00497         statMaxBlockWidth = 0;
00498         statMinBlockHeight = INF;
00499         statMaxBlockHeight = 0;
00500 
00501         statMinGridWidth = INF;
00502         statMaxGridWidth = 0;
00503         statMinGridHeight = INF;
00504         statMaxGridHeight = 0;
00505 }
00506 
00507 /** Empty stub for the superclass virtual method.
00508  * @copydoc IAligner::printStageStatistics
00509  */
00510 void AbstractBlockAligner::printStageStatistics(FILE* file) {
00511 }
00512 
00513 /** Empty stub for the superclass virtual method.
00514  * @copydoc IAligner::printFinalStatistics
00515  */
00516 void AbstractBlockAligner::printFinalStatistics(FILE* file) {
00517 }
00518 
00519 /*
00520  * This method returns a progress string that is printed periodically.
00521  */
00522 const char* AbstractBlockAligner::getProgressString() const {
00523         return "";
00524 }
00525 
00526 /*
00527  *
00528  */
00529 long long AbstractBlockAligner::getProcessedCells() {
00530         return 0; // Used to calculate the MCUPS performance metric
00531 }
00532 
00533 /**
00534  * Allocate vectors after sequence is set.
00535  */
00536 void AbstractBlockAligner::allocateStructures() {
00537         /*
00538          * Allocates the first row of each block. This vector is transferred
00539          * from on block to the other, in the vertical direction.
00540          */
00541         int grid_width = getGrid()->getGridWidth();
00542         row = new cell_t*[grid_width];
00543         for (int j=0; j<grid_width; j++) {
00544                 int block_width = getGrid()->getBlockWidth(j,0);
00545                 row[j] = new cell_t[block_width];
00546         }
00547 
00548         /*
00549          * Allocates the first column of each block. This vector is transferred
00550          * from on block to the other, in the horizontal direction.
00551          */
00552         int grid_height = getGrid()->getGridHeight();
00553         col = new cell_t*[grid_height];
00554         for (int i=0; i<grid_height; i++) {
00555                 int block_height = getGrid()->getBlockHeight(0,i);
00556                 col[i] = new cell_t[block_height+1];
00557         }
00558 
00559 
00560 
00561         grid_scores = new score_t*[ grid_width ];
00562         for( int j = 0; j < grid_width; ++j ){
00563                 grid_scores[j] = new score_t[ grid_height ];
00564                 for( int i = 0; i < grid_height; ++i ) {
00565                         grid_scores[j][i].score = -INF;
00566                 }
00567         }
00568 }
00569 
00570 /**
00571  * Deallocate vectors after sequence is unset.
00572  */
00573 void AbstractBlockAligner::deallocateStructures() {
00574         if (getGrid() == NULL) {
00575                 return;
00576         }
00577         int grid_width = getGrid()->getGridWidth();
00578         int grid_height = getGrid()->getGridHeight();
00579 
00580         if (row != NULL) {
00581                 for (int j = 0; j < grid_width; ++j) {
00582                         delete[] row[j];
00583                 }
00584                 delete[] row;
00585                 row = NULL;
00586         }
00587         if (col != NULL) {
00588                 for (int i = 0; i < grid_height; ++i) {
00589                         delete[] col[i];
00590                 }
00591                 delete[] col;
00592                 col = NULL;
00593         }
00594         if(grid_scores != NULL) {
00595                 for( int j = 0; j < grid_width; ++j ){
00596                         delete[] grid_scores[j];
00597                 }
00598                 delete[] grid_scores;
00599                 grid_scores = NULL;
00600         }
00601 }
00602 
00603 /**
00604  * Returns true if block (bx, by) can be pruned.
00605  *
00606  * @param bx horizontal block coordinate
00607  * @param by vertical block coordinate
00608  * @return pruned status of the block.
00609  */
00610 bool AbstractBlockAligner::isBlockPruned(int bx, int by) const {
00611         return (blockPruner != NULL && blockPruner->isBlockPruned(bx, by));
00612 }
00613 
00614 /**
00615  * Updates the pruning status accordingly to the block score.
00616  *
00617  * @param bx horizontal block coordinate
00618  * @param by vertical block coordinate
00619  * @param score the score of block at coordinate $(bx,by)$
00620  */
00621 void AbstractBlockAligner::pruningUpdate(int bx, int by, int score) {
00622         if (blockPruner != NULL) {
00623                 blockPruner->pruningUpdate(bx, by, score);
00624         }
00625 }
00626 
00627 /**
00628  * Defines the preferred block/grid sizes. Used as a hint.
00629  *
00630  * @param preferredBlockSize the preferred maximum size of a block.
00631  * @param preferredGridSize the preferred minimum grid size.
00632  */
00633 void AbstractBlockAligner::setPreferredSizes(int preferredBlockSize,    int preferredGridSize) {
00634         if (preferredBlockSize > 0) {
00635                 this->preferredBlockSize = preferredBlockSize;
00636         }
00637         if (preferredGridSize > 0) {
00638                 this->preferredGridSize = preferredGridSize;
00639         }
00640 }
00641 
00642 
00643 
00644