• Aucun résultat trouvé

Chapitre 3 Lecteur de format BigWig en C++ moderne

3.5 Programmer un lecteur BigWig en C++ moderne

Notre motivation principale était de supporter le format BigWig pour l’outil VAP (Coulombe, et al., 2014) développé dans notre laboratoire et codé en C++. Tel que mentionné, l’utilitaire de Kent, quoi que fonctionnel, est écrit dans un langage et dans une méthode de programmation qui nuit à son extensibilité. L’absence de code de lecture du format BigWig écrit en C++ moderne ainsi que la facilité que nous avons eu à travailler avec le code du lecteur d’IGV nous ont amené à vouloir implémenter une version moderne et orientée objet en C++ d’un outil de lecture BigWig. Ceci répondait également à trois besoins internes et externes que la librairie de Kent ne satisfait pas :

 Offrir une interface distincte pour lire le format BigWig ;

 Écrire cet interface en code orienté objet moderne pour permettre son extension par des sources externes advenant des nécessités futures ;

 Et rendre l’interface compatible avec des itérateurs C++ moderne pour permettre de travailler avec les algorithmes standards de la STL.

Pour expliquer le troisième besoin, nous suggérons (Nelson, 1995) qui explique bien les avantages d’offrir un itérateur standardisé en C++.

3.5.1 Code de lecture moderne

Dans cette section, nous allons présenter les éléments qui composent notre lecteur de code C++. Nous commencerons par présenter les outils externes que nous avons intégrés à notre code pour remplir des fonctionnalités spécifiques. Ensuite, nous discuterons de sa structure interne et de son interface externe suivie de quelques exemples d’utilisation de nos itérateurs. Finalement, nous donnerons des exemples de programmes qui intègrent notre lecteur et nous expliquerons comment intégrer le code dans de futurs outils.

3.5.2 Utilisation de Boost

La librairie de code Boost est une librairie libre accès revue par les pairs qui est un standard dans le domaine du développement C++ (Schling, 2011). Les données dans les feuilles de l’arbre R sont compressées avec l’algorithme d’encryption de l’outil gzip qui est accessible par la librairie de Boost Iostreams. Pour accéder au contenu d’une feuille et garantir le bon fonctionnement de notre routine de décompression, nous avons décidé d’utiliser cette implémentation dans notre librairie.

3.5.3 Utilisation et structure générale du code de lecture

Deux objets sont essentiels pour utiliser correctement notre code de lecture : le BWReader et le BWIterator. Le BWReader est l’objet qui encapsule l’ouverture d’un fichier BigWig. Ouvrir un fichier avec un objet BWReader est assez simple :

BWReader myBWFile(PathtoMyFile);

Utiliser un BWReader passe par l’utilisation d’un objet BWIterator. En soit, le BWReader ne fait que répondre à des requêtes en fournissant un BWIterator qui possède une liste des feuilles qui répondent à une requête spécifique. Par exemple, voici une requête dans le cas où l'usager désire un BWIterator qui va parcourir l’ensemble des données :

BWIterator myBigIterator = myBWFile.getBigWigIterator();

Ou si l'usager désire un BWIterator qui parcourt seulement les données du chr1 :

BWIterator myBigIterator = myBWFile.getBigWigIterator(‘chr1’, 0, 0);

Et ainsi de suite pour toutes les régions souhaitées. Après avoir obtenu l’accès à un BWIterator, la syntaxe pour accéder aux données est soit celle d’un itérateur Java, soit celle d’un itérateur standard C++.

Dans l’exemple ci-dessous, l’utilitaire déclare deux itérateurs qui ciblent respectivement les régions 1400-1700 et 2400-4700 du chr21 de notre fichier. Ensuite il itère à travers tous les éléments du premier itérateur et écrit les données à l’écran :

std ::ifstream fis.open("monfichier.bigwig", ios::in | ios::binary); BBFileReader monLecteurBW("monfichier.bigwig",fis);

BWIterator monIterateur =

monLecteurBW.getBigWigIterator("chr21",1400,"chr21",1700); BWIterator autreIterateur =

std::cout <<myIterator->getEndBase()<<" "; std::cout <<myIterator->getChromosome()<<" "; std::cout <<myIterator->getWigValue()<<"\n"; }

Cet exemple illustre bien la facilité d’utilisation de notre code.

De plus, dû à la structure orientée objet du code, il serait facile de spécialiser l’itérateur pour des besoins spécifiques d’un programme. Nous pourrions, par exemple, hériter de l’objet BWIterator et écrire un FilteringBWIterator qui pourrait ignorer automatiquement toutes les valeurs qui ne correspondent pas à une condition spécifique. Alternativement, il serait facile d’implémenter un HttpBWIterator permettant d’écrire le résultat d’une requête dans un format compatible à un service http transmis via l’internet.

Aussi, dans l’optique de développer des utilitaires de lecture efficaces et polyvalents, la structure de la classe BWReader permettrait son intégration dans un module de lecture générale de formats génomiques indexés, ce qui permettrait à l’usager de lire de manière transparente les formats BigWig/BAM/CRAM et tout autre futur format indexé. Ceci aurait été difficile à implémenter avec une structure de code procédurale telle que celle de l’utilitaire de Kent.

Finalement, l’encapsulation des fonctionnalités dans un objet bien défini rend trivial son intégration dans des utilitaires externes. Quand nous avons rajouté la fonctionnalité de lecture BigWig au programme VAP, le procédé d’intégration lui-même n’a pris que quelques heures.

3.5.4 Intégration dans des outils existants et futurs

Présentement, notre code de lecture est utilisé dans trois projets différents de notre laboratoire. Tel que mentionné précédemment, il a d’abord été intégré dans l’outil VAP. Le code a ensuite

été rajouté directement dans le module de lecture de la librairie NGS++ présenté au chapitre 2 afin de permettre l’accès à des fichiers BigWig de manière transparente et d’utiliser l’interface Python de cette librairie. Finalement, le module de conversion HDF5 de l’outil GeEC présenté au chapitre 4 utilise également notre code de lecture.

Dans les cas présentés, les outils ont intégré directement le code de lecture. Celui-ci inclut la librairie Boost nécessaire. Leur seul dépendance est ainsi un compilateur C++ supportant le standard de C++11. Cependant, il est également possible d’utiliser le code de lecture sous forme de librairie statique.