source: XIOS/dev/branch_openmp/src/io/onetcdf4.cpp @ 1460

Last change on this file since 1460 was 1460, checked in by yushan, 6 years ago

branch_openmp merged with XIOS_DEV_CMIP6@1459

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
File size: 23.2 KB
Line 
1#include <fstream>
2
3#include "onetcdf4.hpp"
4#include "group_template.hpp"
5//#include "mpi.hpp"
6#include "netcdf.hpp"
7#include "netCdfInterface.hpp"
8#include "netCdfException.hpp"
9#include "timer.hpp"
10
11namespace xios
12{
13      /// ////////////////////// Définitions ////////////////////// ///
14
15      CONetCDF4::CONetCDF4(const StdString& filename, bool append, bool useClassicFormat,
16                                                        bool useCFConvention,
17                           const ep_lib::MPI_Comm* comm, bool multifile, const StdString& timeCounterName)
18        : path()
19        , wmpi(false)
20        , useClassicFormat(useClassicFormat)
21        , useCFConvention(useCFConvention)
22      {
23         this->initialize(filename, append, useClassicFormat, useCFConvention, comm, multifile, timeCounterName);
24      }
25
26      //---------------------------------------------------------------
27
28      CONetCDF4::~CONetCDF4(void)
29      {
30      }
31
32      ///--------------------------------------------------------------
33
34      void CONetCDF4::initialize(const StdString& filename, bool append, bool useClassicFormat, bool useCFConvention, 
35                                 const ep_lib::MPI_Comm* comm, bool multifile, const StdString& timeCounterName)
36      {
37         this->useClassicFormat = useClassicFormat;
38         this->useCFConvention = useCFConvention;
39
40         int mode = useClassicFormat ? 0 : NC_NETCDF4;
41
42         // Don't use parallel mode if there is only one process
43         if (comm)
44         {
45            int commSize = 0;
46            ep_lib::MPI_Comm_size(*comm, &commSize);
47            if (commSize <= 1)
48               comm = NULL;
49         }
50         wmpi = comm && !multifile;
51         ep_lib::MPI_Info info_null;
52
53         if (wmpi)
54            mode |= useClassicFormat ? NC_PNETCDF : NC_MPIIO;
55
56         // If the file does not exist, we always create it
57         if (!append || !std::ifstream(filename.c_str()))
58         {
59            CTimer::get("Files : create").resume();
60            if (wmpi)
61               CNetCdfInterface::createPar(filename, mode, *(static_cast<MPI_Comm*>(comm->mpi_comm)), *(static_cast<MPI_Info*>(info_null.mpi_info)), this->ncidp);
62               //CNetCdfInterface::createPar(filename, mode, *(static_cast<MPI_Comm*>(comm->mpi_comm)), info_null.mpi_info, this->ncidp);
63            else
64               CNetCdfInterface::create(filename, mode, this->ncidp);
65            CTimer::get("Files : create").suspend();
66 
67            this->appendMode = false;
68         }
69         else
70         {
71            mode |= NC_WRITE;
72            CTimer::get("Files : open").resume();
73            if (wmpi)
74               CNetCdfInterface::openPar(filename, mode, *(static_cast<MPI_Comm*>(comm->mpi_comm)), *(static_cast<MPI_Info*>(info_null.mpi_info)), this->ncidp);
75               //CNetCdfInterface::openPar(filename, mode, *(static_cast<MPI_Comm*>(comm->mpi_comm)), info_null.mpi_info, this->ncidp);
76            else
77               CNetCdfInterface::open(filename, mode, this->ncidp);
78            CTimer::get("Files : open").suspend();
79            this->appendMode = true;
80         }
81
82         // If the classic NetCDF format is used, we enable the "no-fill mode" globally.
83         // This is done per variable for the NetCDF4 format.
84         if (useClassicFormat)
85            CNetCdfInterface::setFill(this->ncidp, false);
86
87         this->timeCounterName = timeCounterName;
88      }
89
90      void CONetCDF4::close()
91      {
92        CTimer::get("Files : close").resume();
93        CNetCdfInterface::close(this->ncidp);
94        CTimer::get("Files : close").suspend();
95      }
96
97      //---------------------------------------------------------------
98
99      void CONetCDF4::definition_start(void)
100      {
101         CNetCdfInterface::reDef(this->ncidp);
102      }
103
104      //---------------------------------------------------------------
105
106      void CONetCDF4::definition_end(void)
107      {
108         CNetCdfInterface::endDef(this->ncidp);
109      }
110
111      //---------------------------------------------------------------
112
113      int CONetCDF4::getCurrentGroup(void)
114      {
115         return this->getGroup(this->getCurrentPath());
116      }
117
118      //---------------------------------------------------------------
119
120      int CONetCDF4::getGroup(const CONetCDF4Path& path)
121      {
122         int retvalue = this->ncidp;
123
124         CONetCDF4Path::const_iterator it = path.begin(), end = path.end();
125
126         for (; it != end; it++)
127         {
128            const StdString& groupid = *it;
129            CNetCdfInterface::inqNcId(retvalue, groupid, retvalue);
130         }
131         return retvalue;
132      }
133
134      //---------------------------------------------------------------
135
136      int CONetCDF4::getVariable(const StdString& varname)
137      {
138         int varid = 0;
139         int grpid = this->getCurrentGroup();
140         CNetCdfInterface::inqVarId(grpid, varname, varid);
141         return varid;
142      }
143
144      //---------------------------------------------------------------
145
146      int CONetCDF4::getDimension(const StdString& dimname)
147      {
148         int dimid = 0;
149         int grpid = this->getCurrentGroup();
150         CNetCdfInterface::inqDimId(grpid, dimname, dimid);
151         return dimid;
152      }
153
154      //---------------------------------------------------------------
155
156      int CONetCDF4::getUnlimitedDimension(void)
157      {
158         int dimid = 0;
159         int grpid = this->getCurrentGroup();
160         CNetCdfInterface::inqUnLimDim(grpid, dimid);
161         return dimid;
162      }
163
164      StdString CONetCDF4::getUnlimitedDimensionName(void)
165      {
166         int grpid = this->getGroup(path);
167         int dimid = this->getUnlimitedDimension();
168
169         StdString dimname;
170         if (dimid != -1)
171           CNetCdfInterface::inqDimName(grpid, dimid, dimname);
172         return dimname;
173      }
174
175      //---------------------------------------------------------------
176
177      std::vector<StdSize> CONetCDF4::getDimensions(const StdString& varname)
178      {
179         StdSize size = 0;
180         std::vector<StdSize> retvalue;
181         int grpid = this->getCurrentGroup();
182         int varid = this->getVariable(varname);
183         int nbdim = 0, *dimid = NULL;
184
185         CNetCdfInterface::inqVarNDims(grpid, varid, nbdim);
186         dimid = new int[nbdim]();
187         CNetCdfInterface::inqVarDimId(grpid, varid, dimid);
188
189         for (int i = 0; i < nbdim; i++)
190         {
191            CNetCdfInterface::inqDimLen(grpid, dimid[i], size);
192            if (size == NC_UNLIMITED)
193                size = UNLIMITED_DIM;
194            retvalue.push_back(size);
195         }
196         delete [] dimid;
197         return retvalue;
198      }
199
200      std::vector<std::string> CONetCDF4::getDimensionsIdList(const std::string* _varname)
201      {
202         int nDimNull = 0;
203         int nbdim = 0, *dimid = NULL;
204         int grpid = this->getCurrentGroup();
205         int varid = (_varname != NULL) ? this->getVariable(*_varname) : NC_GLOBAL;
206         std::vector<std::string> retvalue;
207
208         if (_varname != NULL)
209         {
210            CNetCdfInterface::inqVarNDims(grpid, varid, nbdim);
211            dimid = new int[nbdim]();
212            CNetCdfInterface::inqVarDimId(grpid, varid, dimid);
213         }
214         else
215         {
216            CNetCdfInterface::inqDimIds(grpid, nbdim, NULL, 1);
217            dimid = new int[nbdim]();
218            CNetCdfInterface::inqDimIds(grpid, nDimNull, dimid, 1);
219         }
220
221         for (int i = 0; i < nbdim; i++)
222         {
223            std::string dimname;
224            CNetCdfInterface::inqDimName(grpid, dimid[i], dimname);
225            retvalue.push_back(dimname);
226         }
227         delete [] dimid;
228
229         return retvalue;
230      }
231
232      //---------------------------------------------------------------
233
234      void CONetCDF4::getTimeAxisBounds(CArray<double,2>& timeAxisBounds, const StdString& name, bool collective)
235      {
236        int grpid = this->getCurrentGroup();
237        int varid = this->getVariable(name);
238
239        std::vector<StdSize> start(2), count(2);
240        start[0] = 0;
241        // Find out how many temporal records have been written already to the file we are opening
242        int ncUnlimitedDimId;
243        CNetCdfInterface::inqUnLimDim(this->ncidp, ncUnlimitedDimId);
244        CNetCdfInterface::inqDimLen(this->ncidp, ncUnlimitedDimId, count[0]);
245        start[1] = 0;
246        count[1] = 2;
247
248        timeAxisBounds.resize(count[1], count[0]);
249
250        if (this->wmpi && collective)
251          CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE);
252        if (this->wmpi && !collective)
253          CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT);
254
255        CNetCdfInterface::getVaraType(grpid, varid, &start[0], &count[0], timeAxisBounds.dataFirst());
256      }
257
258      void CONetCDF4::getTimeAxisBounds(CArray<double,2>& timeAxisBounds, const StdString& name, bool collective, size_t record)
259      {
260        int grpid = this->getCurrentGroup();
261        int varid = this->getVariable(name);
262
263        std::vector<StdSize> start(2), count(2);
264        start[0] = record;
265        count[0] = 1 ;
266        start[1] = 0;
267        count[1] = 2;
268
269        timeAxisBounds.resize(2, 1);
270
271        if (this->wmpi && collective)
272          CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE);
273        if (this->wmpi && !collective)
274          CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT);
275
276        CNetCdfInterface::getVaraType(grpid, varid, &start[0], &count[0], timeAxisBounds.dataFirst());
277      }
278
279
280
281      const CONetCDF4::CONetCDF4Path& CONetCDF4::getCurrentPath(void) const
282      { return this->path; }
283
284      void CONetCDF4::setCurrentPath(const CONetCDF4Path& path)
285      { this->path = path; }
286
287      //---------------------------------------------------------------
288
289      int CONetCDF4::addGroup(const StdString& name)
290      {
291         int retvalue = 0;
292         int grpid = this->getCurrentGroup();
293         CNetCdfInterface::defGrp(grpid, name, retvalue);
294         return retvalue;
295      }
296
297      //---------------------------------------------------------------
298
299      int CONetCDF4::addDimension(const StdString& name, const StdSize size)
300      {
301         int retvalue = 0;
302         int grpid = this->getCurrentGroup();
303         if (size != UNLIMITED_DIM)
304            CNetCdfInterface::defDim(grpid, name, size, retvalue);
305         else
306            CNetCdfInterface::defDim(grpid, name, NC_UNLIMITED, retvalue);
307         return retvalue;
308      }
309
310      //---------------------------------------------------------------
311
312      int CONetCDF4::addVariable(const StdString& name, nc_type type,
313                                 const std::vector<StdString>& dim, int compressionLevel)
314      {
315         int varid = 0;
316         std::vector<int> dimids;
317         std::vector<StdSize> dimsizes;
318         int dimSize = dim.size();
319         
320         StdSize size;
321         StdSize totalSize;
322         StdSize maxSize = 1024 * 1024 * 256; // == 2GB/8 if output double
323
324         int grpid = this->getCurrentGroup();
325
326         std::vector<StdString>::const_iterator it = dim.begin(), end = dim.end();
327
328         for (int idx = 0; it != end; it++, ++idx)
329         {
330            const StdString& dimid = *it;
331            dimids.push_back(this->getDimension(dimid));
332            CNetCdfInterface::inqDimLen(grpid, this->getDimension(dimid), size);
333            if (size == NC_UNLIMITED) size = 1;
334            dimsizes.push_back(size);
335         }
336
337         CNetCdfInterface::defVar(grpid, name, type, dimids.size(), &dimids[0], varid);
338
339         // The classic NetCDF format does not support chunking nor fill parameters
340         if (!useClassicFormat)
341         {
342            // set chunksize : size of one record
343            // but must not be > 2GB (netcdf or HDF5 problem)
344            totalSize = 1;
345            for (vector<StdSize>::reverse_iterator it = dimsizes.rbegin(); it != dimsizes.rend(); ++it)
346            {
347              totalSize *= *it;
348              if (totalSize >= maxSize) *it = 1;
349            }
350            int storageType = (0 == dimSize) ? NC_CONTIGUOUS : NC_CHUNKED;
351            CNetCdfInterface::defVarChunking(grpid, varid, storageType, &dimsizes[0]);
352            CNetCdfInterface::defVarFill(grpid, varid, true, NULL);
353         }
354
355         setCompressionLevel(name, compressionLevel) ;
356         
357         return varid;
358      }
359
360      //---------------------------------------------------------------
361
362      void CONetCDF4::setCompressionLevel(const StdString& varname, int compressionLevel)
363      {
364         if (compressionLevel < 0 || compressionLevel > 9)
365           ERROR("void CONetCDF4::setCompressionLevel(const StdString& varname, int compressionLevel)",
366                 "Invalid compression level for variable \"" << varname << "\", the value should range between 0 and 9.");
367         if (compressionLevel && wmpi)
368           ERROR("void CONetCDF4::setCompressionLevel(const StdString& varname, int compressionLevel)",
369                 "Impossible to use compression for variable \"" << varname << "\" when using parallel mode.");
370
371         int grpid = this->getCurrentGroup();
372         int varid = this->getVariable(varname);
373         CNetCdfInterface::defVarDeflate(grpid, varid, compressionLevel);
374      }
375
376      //---------------------------------------------------------------
377
378      template <>
379      void CONetCDF4::addAttribute(const StdString& name, const StdString& value, const StdString* varname)
380      {
381         int grpid = this->getCurrentGroup();
382         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
383         CNetCdfInterface::putAttType(grpid, varid, name, value.size(), value.c_str());
384      }
385
386      //---------------------------------------------------------------
387
388      template <>
389      void CONetCDF4::addAttribute(const StdString& name, const double& value, const StdString* varname)
390      {
391         int grpid = this->getCurrentGroup();
392         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
393         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
394      }
395
396      template <>
397      void CONetCDF4::addAttribute(const StdString& name, const CArray<double,1>& value, const StdString* varname)
398      {
399         int grpid = this->getCurrentGroup();
400         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
401         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
402      }
403      //---------------------------------------------------------------
404
405      template <>
406      void CONetCDF4::addAttribute(const StdString& name, const float& value, const StdString* varname)
407      {
408         int grpid = this->getCurrentGroup();
409         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
410         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
411      }
412
413      template <>
414      void CONetCDF4::addAttribute(const StdString& name, const CArray<float,1>& value, const StdString* varname)
415      {
416         int grpid = this->getCurrentGroup();
417         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
418         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
419      }
420
421      //---------------------------------------------------------------
422
423      template <>
424      void CONetCDF4::addAttribute(const StdString& name, const int& value, const StdString* varname)
425      {
426         int grpid = this->getCurrentGroup();
427         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
428         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
429      }
430
431      template <>
432      void CONetCDF4::addAttribute(const StdString& name, const CArray<int,1>& value, const StdString* varname)
433      {
434         int grpid = this->getCurrentGroup();
435         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
436         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
437      }
438
439      template <>
440      void CONetCDF4::addAttribute(const StdString& name, const short int& value, const StdString* varname)
441      {
442         int grpid = this->getCurrentGroup();
443         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
444         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
445      }
446
447      template <>
448      void CONetCDF4::addAttribute(const StdString& name, const CArray<short int,1>& value, const StdString* varname)
449      {
450         int grpid = this->getCurrentGroup();
451         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
452         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
453      }
454
455      template <>
456      void CONetCDF4::addAttribute(const StdString& name, const long int& value, const StdString* varname)
457      {
458         int grpid = this->getCurrentGroup();
459         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
460         CNetCdfInterface::putAttType(grpid, varid, name, 1, &value);
461      }
462
463      template <>
464      void CONetCDF4::addAttribute(const StdString& name, const CArray<long int,1>& value, const StdString* varname)
465      {
466         int grpid = this->getCurrentGroup();
467         int varid = (varname == NULL) ? NC_GLOBAL : this->getVariable(*varname);
468         CNetCdfInterface::putAttType(grpid, varid, name, value.numElements(), value.dataFirst());
469      }
470
471      //---------------------------------------------------------------
472
473      void CONetCDF4::getWriteDataInfos(const StdString& name, StdSize record, StdSize& array_size,
474                                        std::vector<StdSize>& sstart,
475                                        std::vector<StdSize>& scount,
476                                        const std::vector<StdSize>* start,
477                                        const std::vector<StdSize>* count)
478      {
479         std::vector<std::size_t> sizes  = this->getDimensions(name);
480         if (sizes.size()==0) 
481         {
482            array_size=1 ;
483            sstart.push_back(0);
484            scount.push_back(1);
485         }
486         else
487         {
488           std::vector<std::string> iddims = this->getDimensionsIdList (&name);
489           std::vector<std::size_t>::const_iterator
490           it  = sizes.begin(), end = sizes.end();
491           int i = 0;
492
493           if (iddims.begin()->compare(timeCounterName) == 0)
494           {
495             sstart.push_back(record);
496             scount.push_back(1);
497              if ((start == NULL) &&
498                  (count == NULL)) i++;
499              it++;
500           }
501
502           for (;it != end; it++)
503           {
504              if ((start != NULL) && (count != NULL))
505              {
506                 sstart.push_back((*start)[i]);
507                 scount.push_back((*count)[i]);
508                 array_size *= (*count)[i];
509                 i++;
510              }
511              else
512              {
513                 sstart.push_back(0);
514                 scount.push_back(sizes[i]);
515                 array_size *= sizes[i];
516                 i++;
517              }
518           }
519
520         }
521      }
522
523
524      template <>
525      void CONetCDF4::writeData_(int grpid, int varid,
526                                 const std::vector<StdSize>& sstart,
527                                 const std::vector<StdSize>& scount, const double* data)
528      {
529         CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
530      }
531
532      //---------------------------------------------------------------
533
534      template <>
535      void CONetCDF4::writeData_(int grpid, int varid,
536                                 const std::vector<StdSize>& sstart,
537                                 const std::vector<StdSize>& scount, char* data)
538      {
539          CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
540      }
541     
542      template <>
543
544      void CONetCDF4::writeData_(int grpid, int varid,
545                                 const std::vector<StdSize>& sstart,
546                                 const std::vector<StdSize>& scount, const int* data)
547      {
548          CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
549      }
550      //---------------------------------------------------------------
551
552      template <>
553      void CONetCDF4::writeData_(int grpid, int varid,
554                                 const std::vector<StdSize>& sstart,
555                                 const std::vector<StdSize>& scount, const float* data)
556      {
557          CNetCdfInterface::putVaraType(grpid, varid, &sstart[0], &scount[0], data);
558      }
559
560      //---------------------------------------------------------------
561
562      void CONetCDF4::writeData(const CArray<int, 2>& data, const StdString& name)
563      {
564         int grpid = this->getCurrentGroup();
565         int varid = this->getVariable(name);
566         StdSize array_size = 1;
567         std::vector<StdSize> sstart, scount;
568
569         this->getWriteDataInfos(name, 0, array_size,  sstart, scount, NULL, NULL);
570
571         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
572
573      }
574
575      void CONetCDF4::writeTimeAxisData(const CArray<double, 1>& data, const StdString& name,
576                                        bool collective, StdSize record, bool isRoot)
577      {
578         int grpid = this->getCurrentGroup();
579         int varid = this->getVariable(name);
580
581         map<int,size_t>::iterator it=timeAxis.find(varid);
582         if (it == timeAxis.end()) timeAxis[varid] = record;
583         else
584         {
585           if (it->second >= record) return;
586           else it->second =record;
587         }
588
589         StdSize array_size = 1;
590         std::vector<StdSize> sstart, scount;
591
592         if (this->wmpi && collective)
593            CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE);
594         if (this->wmpi && !collective)
595            CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT);
596
597         this->getWriteDataInfos(name, record, array_size,  sstart, scount, NULL, NULL);
598         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
599       }
600
601      void CONetCDF4::writeTimeAxisDataBounds(const CArray<double, 1>& data, const StdString& name,
602                                        bool collective, StdSize record, bool isRoot)
603      {
604         int grpid = this->getCurrentGroup();
605         int varid = this->getVariable(name);
606
607         map<int,size_t>::iterator it=timeAxis.find(varid);
608         if (it == timeAxis.end()) timeAxis[varid] = record;
609         else
610         {
611           if (it->second >= record) return;
612           else it->second =record;
613         }
614
615         StdSize array_size = 1;
616         std::vector<StdSize> sstart, scount;
617
618         if (this->wmpi && collective)
619            CNetCdfInterface::varParAccess(grpid, varid, NC_COLLECTIVE);
620         if (this->wmpi && !collective)
621            CNetCdfInterface::varParAccess(grpid, varid, NC_INDEPENDENT);
622
623         this->getWriteDataInfos(name, record, array_size,  sstart, scount, NULL, NULL);
624         this->writeData_(grpid, varid, sstart, scount, data.dataFirst());
625       }
626
627
628      //---------------------------------------------------------------
629
630      bool CONetCDF4::varExist(const StdString& varname)
631      {
632         int grpid = this->getCurrentGroup();
633         return CNetCdfInterface::isVarExisted(grpid, varname);
634      }
635
636      bool CONetCDF4::dimExist(const StdString& dimname)
637      {
638         int grpid = this->getCurrentGroup();
639         return CNetCdfInterface::isDimExisted(grpid, dimname);
640      }
641
642      void CONetCDF4::sync(void)
643      {
644         CNetCdfInterface::sync(this->ncidp);
645      }
646      ///--------------------------------------------------------------
647 } // namespace xios
Note: See TracBrowser for help on using the repository browser.