4.3.4.1.3 : La fonction générale du programme
Maintenant, implémentons la fonctions générale :
1 2 3 4 5 6 7 8 9 10 11 12 |
///Simulate the images /** @param nbRow : number of rows of the images to be created * @param nbCol : number of columns of the images to be created * @param nbImage : number of images to be created * @param nbExtraStep : number of extra steps to be computed between images * @param killRate : rate of the process which converts V into P * @param feedRate : rate of the process which feeds U and drains U, V and P * @param dt : time interval between two computation * @param outputFile : name of the file to be created * @return true on succsess, false otherwise */ bool simulateImage(size_t nbRow, size_t nbCol, size_t nbImage, size_t nbExtraStep, float killRate, float feedRate, float dt, const std::string & outputFile){ |
Nous allons commencer par indiquer quelques paramètres utiles pour l'utilisateur :
1 |
std::cout << "simulateImage : nbImage = "<<nbImage<<", nbRow = " << nbRow << ", nbCol = " << nbCol << std::endl; |
Ensuite, nous devons définir l'ensemble de nos images en HDF5 :
1 2 3 |
MatrixHdf5 fullMat;
fullMat.setAllDim(nbCol, nbRow);
fullMat.resize(nbImage);
|
On créé et on initialise les PTensor et les pointeurs de nos images temporaires :
1 2 3 |
PTensor<float> tmpInU, tmpInV, tmpOutU, tmpOutV; float *tmpU1 = NULL, *tmpU2 = NULL, *tmpV1 = NULL, *tmpV2 = NULL; allocate_temporary(tmpU1, tmpU2, tmpV1, tmpV2, tmpInU, tmpInV, tmpOutU, tmpOutV, nbRow, nbCol); |
On définit notre stencil 3x3 (avec éventuellement des coéfficients plus sérieux mais qui donnent des résultats moins rigolos) :
1 2 3 4 5 6 7 8 9 10 |
long nbStencilRow(3l), nbStencilCol(3l); float diffudionRateU(0.1f), diffusionRateV(0.05f); //This matrix of neigbour exchange is quite accurate but gives not so fun results // float matDeltaSquare[] = {0.05f, 0.2f, 0.05f, // 0.2f, 0.0f, 0.2f, // 0.05f, 0.2f, 0.05f}; float matDeltaSquare[] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; |
Cependant, nous devons maintenant convertir tout nos temporaires afin qu'ils soient complètement vectorisables :
1 2 3 4 5 6 |
//Let's convert these temporaries into intrinsics temporaries PTensor<float> tmpVecInU(AllocMode::ALIGNED), tmpVecInV(AllocMode::ALIGNED), tmpVecOutU(AllocMode::ALIGNED), tmpVecOutV(AllocMode::ALIGNED); tmpVecInU.fromScalToVecNeigbhour(tmpInU, PLIB_VECTOR_SIZE_FLOAT); tmpVecOutU.fromScalToVecNeigbhour(tmpOutU, PLIB_VECTOR_SIZE_FLOAT); tmpVecInV.fromScalToVecNeigbhour(tmpInV, PLIB_VECTOR_SIZE_FLOAT); tmpVecOutV.fromScalToVecNeigbhour(tmpOutV, PLIB_VECTOR_SIZE_FLOAT); |
La vectorisation de la matrice qui définit les poids du gradient :
1 2 |
PTensor<float> vecMatDeltaSquare(AllocMode::ALIGNED, nbStencilRow, nbStencilCol*PLIB_VECTOR_SIZE_FLOAT); reshuffle_broadcastTensor(vecMatDeltaSquare.getData(), matDeltaSquare, nbStencilRow, nbStencilCol, 0lu, PLIB_VECTOR_SIZE_FLOAT); |
On définit les pointeurs correspondants :
1 2 3 4 5 |
float * tmpVecU1 = tmpVecInU.getData(); float * tmpVecU2 = tmpVecOutU.getData(); float * tmpVecV1 = tmpVecInV.getData(); float * tmpVecV2 = tmpVecOutV.getData(); float * ptrVecMatStencil = vecMatDeltaSquare.getData(); |
On défint la nouvelle taille des matrices :
1 2 |
size_t nbVecRow(tmpVecInV.getFullNbRow()), nbVecCol(tmpVecInV.getNbCol()); PTensor<float> tmpScalOutV(AllocMode::ALIGNED); |
On créé notre barre de chargement :
1 2 |
ProgressTime progress(nbImage);
progress.start();
|
On boucle sur toutes les images que l'on veut créer :
1 |
for(size_t i(0lu); i < nbImage; ++i){ |
Petite mise à jour de la barre de chargement :
1 |
progress.print(); |
On boucle sur les image supplémentaires à calculer entre deux images à sauvegarder :
1 |
for(size_t j(0lu); j < nbExtraStep; ++j){ |
On appelle notre calcul de Gray Scott :
1 2 3 |
grayscott_propagation(tmpVecU2, tmpVecV2, tmpVecU1, tmpVecV1, nbVecRow, nbVecCol, ptrVecMatStencil, nbStencilRow, nbStencilCol, diffudionRateU, diffusionRateV, feedRate, killRate, dt); |
Il ne faut pas oublier que notre calcul se fait que sur la moitier des valeurs duppliquées, il faut donc les mettre à jour :
1 2 3 |
//Let's update the dupplicated values reshuffle_updateDupplicateVecNeighbour(tmpVecU2, nbVecRow, nbVecCol, PLIB_VECTOR_SIZE_FLOAT); reshuffle_updateDupplicateVecNeighbour(tmpVecV2, nbVecRow, nbVecCol, PLIB_VECTOR_SIZE_FLOAT); |
On interverti les pointeurs input et output afin d'éviter des copie inutiles :
1 2 3 4 |
///Let's swap the pointer
swapValue(tmpVecU1, tmpVecU2);
swapValue(tmpVecV1, tmpVecV2);
}
|
On récupère l'image que l'on veut sauvegarder (en faisant attention car on interverti les pointeurs régulièrement) :
1 2 3 4 5 |
if(tmpVecV1 != tmpVecOutV.getData()){ tmpScalOutV.fromVecToScalNeigbhour(tmpVecOutV); }else{ tmpScalOutV.fromVecToScalNeigbhour(tmpVecInV); //The pointers were swaped } |
On sauvegarde l'image que l'on veut :
1 2 |
fullMat.setRow(i, tmpScalOutV.getData()); } |
On termine la barre de chargement :
1 2 |
progress.finish(); std::cerr << "Done" << std::endl; |
` On écrit le fichier HDF5 :
1 2 |
//Let's save the output file
fullMat.write(outputFile);
|
On renvoie true car tout s'est bien passé et on finit la fonction :
1 2 |
return true; } |