source: anuga_core/source/anuga/abstract_2d_finite_volumes/test_domain.py @ 5521

Last change on this file since 5521 was 4932, checked in by steve, 16 years ago
File size: 22.2 KB
Line 
1#!/usr/bin/env python
2
3import unittest
4from math import sqrt
5
6from domain import *
7from anuga.config import epsilon
8from Numeric import allclose, array, ones, Float
9
10
11def add_to_verts(tag, elements, domain):
12    if tag == "mound":
13        domain.test = "Mound"
14
15
16def set_bottom_friction(tag, elements, domain):
17    if tag == "bottom":
18        #print 'bottom - indices',elements
19        domain.set_quantity('friction', 0.09, indices = elements)
20
21def set_top_friction(tag, elements, domain):
22    if tag == "top":
23        #print 'top - indices',elements
24        domain.set_quantity('friction', 1., indices = elements)
25
26
27def set_all_friction(tag, elements, domain):
28    if tag == 'all':
29        new_values = domain.get_quantity('friction').get_values(indices = elements) + 10.0
30
31        domain.set_quantity('friction', new_values, indices = elements)
32
33
34class Test_Domain(unittest.TestCase):
35    def setUp(self):
36        pass
37
38
39    def tearDown(self):
40        pass
41
42
43    def test_simple(self):
44        a = [0.0, 0.0]
45        b = [0.0, 2.0]
46        c = [2.0,0.0]
47        d = [0.0, 4.0]
48        e = [2.0, 2.0]
49        f = [4.0,0.0]
50
51        points = [a, b, c, d, e, f]
52        #bac, bce, ecf, dbe, daf, dae
53        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
54
55        conserved_quantities = ['stage', 'xmomentum', 'ymomentum']
56        other_quantities = ['elevation', 'friction']
57
58        domain = Domain(points, vertices, None,
59                        conserved_quantities, other_quantities)
60        domain.check_integrity()
61
62        for name in conserved_quantities + other_quantities:
63            assert domain.quantities.has_key(name)
64
65
66        assert domain.get_conserved_quantities(0, edge=1) == 0.
67
68
69    def test_conserved_quantities(self):
70
71        a = [0.0, 0.0]
72        b = [0.0, 2.0]
73        c = [2.0,0.0]
74        d = [0.0, 4.0]
75        e = [2.0, 2.0]
76        f = [4.0,0.0]
77
78        points = [a, b, c, d, e, f]
79        #bac, bce, ecf, dbe, daf, dae
80        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
81
82        domain = Domain(points, vertices, boundary=None,
83                        conserved_quantities =\
84                        ['stage', 'xmomentum', 'ymomentum'])
85
86
87        domain.set_quantity('stage', [[1,2,3], [5,5,5],
88                                      [0,0,9], [-6, 3, 3]])
89
90        domain.set_quantity('xmomentum', [[1,2,3], [5,5,5],
91                                          [0,0,9], [-6, 3, 3]])
92
93        domain.check_integrity()
94
95        #Centroids
96        q = domain.get_conserved_quantities(0)
97        assert allclose(q, [2., 2., 0.])
98
99        q = domain.get_conserved_quantities(1)
100        assert allclose(q, [5., 5., 0.])
101
102        q = domain.get_conserved_quantities(2)
103        assert allclose(q, [3., 3., 0.])
104
105        q = domain.get_conserved_quantities(3)
106        assert allclose(q, [0., 0., 0.])
107
108
109        #Edges
110        q = domain.get_conserved_quantities(0, edge=0)
111        assert allclose(q, [2.5, 2.5, 0.])
112        q = domain.get_conserved_quantities(0, edge=1)
113        assert allclose(q, [2., 2., 0.])
114        q = domain.get_conserved_quantities(0, edge=2)
115        assert allclose(q, [1.5, 1.5, 0.])
116
117        for i in range(3):
118            q = domain.get_conserved_quantities(1, edge=i)
119            assert allclose(q, [5, 5, 0.])
120
121
122        q = domain.get_conserved_quantities(2, edge=0)
123        assert allclose(q, [4.5, 4.5, 0.])
124        q = domain.get_conserved_quantities(2, edge=1)
125        assert allclose(q, [4.5, 4.5, 0.])
126        q = domain.get_conserved_quantities(2, edge=2)
127        assert allclose(q, [0., 0., 0.])
128
129
130        q = domain.get_conserved_quantities(3, edge=0)
131        assert allclose(q, [3., 3., 0.])
132        q = domain.get_conserved_quantities(3, edge=1)
133        assert allclose(q, [-1.5, -1.5, 0.])
134        q = domain.get_conserved_quantities(3, edge=2)
135        assert allclose(q, [-1.5, -1.5, 0.])
136
137
138
139    def test_create_quantity_from_expression(self):
140        """Quantity created from other quantities using arbitrary expression
141
142        """
143
144
145        a = [0.0, 0.0]
146        b = [0.0, 2.0]
147        c = [2.0,0.0]
148        d = [0.0, 4.0]
149        e = [2.0, 2.0]
150        f = [4.0,0.0]
151
152        points = [a, b, c, d, e, f]
153        #bac, bce, ecf, dbe, daf, dae
154        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
155
156        domain = Domain(points, vertices, boundary=None,
157                        conserved_quantities =\
158                        ['stage', 'xmomentum', 'ymomentum'],
159                        other_quantities = ['elevation', 'friction'])
160
161
162        domain.set_quantity('elevation', -1)
163
164
165        domain.set_quantity('stage', [[1,2,3], [5,5,5],
166                                      [0,0,9], [-6, 3, 3]])
167
168        domain.set_quantity('xmomentum', [[1,2,3], [5,5,5],
169                                          [0,0,9], [-6, 3, 3]])
170
171        domain.set_quantity('ymomentum', [[3,3,3], [4,2,1],
172                                          [2,4,-1], [1, 0, 1]])
173
174        domain.check_integrity()
175
176
177
178        expression = 'stage - elevation'
179        Q = domain.create_quantity_from_expression(expression)
180
181        assert allclose(Q.vertex_values, [[2,3,4], [6,6,6],
182                                      [1,1,10], [-5, 4, 4]])
183
184        expression = '(xmomentum*xmomentum + ymomentum*ymomentum)**0.5'
185        Q = domain.create_quantity_from_expression(expression)
186
187        X = domain.quantities['xmomentum'].vertex_values
188        Y = domain.quantities['ymomentum'].vertex_values
189
190        assert allclose(Q.vertex_values, (X**2 + Y**2)**0.5)
191
192
193
194    def test_set_quanitities_to_be_monitored(self):
195        """test_set_quanitities_to_be_monitored
196        """
197
198        a = [0.0, 0.0]
199        b = [0.0, 2.0]
200        c = [2.0,0.0]
201        d = [0.0, 4.0]
202        e = [2.0, 2.0]
203        f = [4.0,0.0]
204
205        points = [a, b, c, d, e, f]
206        #bac, bce, ecf, dbe, daf, dae
207        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
208
209
210        domain = Domain(points, vertices, boundary=None,
211                        conserved_quantities =\
212                        ['stage', 'xmomentum', 'ymomentum'],
213                        other_quantities = ['elevation', 'friction', 'depth'])
214
215
216        assert domain.quantities_to_be_monitored is None
217        domain.set_quantities_to_be_monitored(['stage', 'stage-elevation'])
218        assert len(domain.quantities_to_be_monitored) == 2
219        assert domain.quantities_to_be_monitored.has_key('stage')
220        assert domain.quantities_to_be_monitored.has_key('stage-elevation')
221        for key in domain.quantities_to_be_monitored['stage'].keys():
222            assert domain.quantities_to_be_monitored['stage'][key] is None
223
224
225        # Check that invalid requests are dealt with
226        try:
227            domain.set_quantities_to_be_monitored(['yyyyy'])       
228        except:
229            pass
230        else:
231            msg = 'Should have caught illegal quantity'
232            raise Exception, msg
233
234        try:
235            domain.set_quantities_to_be_monitored(['stage-xx'])       
236        except NameError:
237            pass
238        else:
239            msg = 'Should have caught illegal quantity'
240            raise Exception, msg
241
242        try:
243            domain.set_quantities_to_be_monitored('stage', 'stage-elevation')
244        except:
245            pass
246        else:
247            msg = 'Should have caught too many arguments'
248            raise Exception, msg
249
250        try:
251            domain.set_quantities_to_be_monitored('stage', 'blablabla')
252        except:
253            pass
254        else:
255            msg = 'Should have caught polygon as a string'
256            raise Exception, msg       
257
258
259
260        # Now try with a polygon restriction
261        domain.set_quantities_to_be_monitored('xmomentum',
262                                              polygon=[[1,1], [1,3], [3,3], [3,1]],
263                                              time_interval = [0,3])
264        assert domain.monitor_indices[0] == 1
265        assert domain.monitor_time_interval[0] == 0
266        assert domain.monitor_time_interval[1] == 3       
267       
268
269    def test_set_quantity_from_expression(self):
270        """Quantity set using arbitrary expression
271
272        """
273
274
275        a = [0.0, 0.0]
276        b = [0.0, 2.0]
277        c = [2.0,0.0]
278        d = [0.0, 4.0]
279        e = [2.0, 2.0]
280        f = [4.0,0.0]
281
282        points = [a, b, c, d, e, f]
283        #bac, bce, ecf, dbe, daf, dae
284        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
285
286        domain = Domain(points, vertices, boundary=None,
287                        conserved_quantities =\
288                        ['stage', 'xmomentum', 'ymomentum'],
289                        other_quantities = ['elevation', 'friction', 'depth'])
290
291
292        domain.set_quantity('elevation', -1)
293
294
295        domain.set_quantity('stage', [[1,2,3], [5,5,5],
296                                      [0,0,9], [-6, 3, 3]])
297
298        domain.set_quantity('xmomentum', [[1,2,3], [5,5,5],
299                                          [0,0,9], [-6, 3, 3]])
300
301        domain.set_quantity('ymomentum', [[3,3,3], [4,2,1],
302                                          [2,4,-1], [1, 0, 1]])
303
304
305
306
307        domain.set_quantity('depth', expression = 'stage - elevation')
308
309        domain.check_integrity()
310
311
312
313
314        Q = domain.quantities['depth']
315
316        assert allclose(Q.vertex_values, [[2,3,4], [6,6,6],
317                                      [1,1,10], [-5, 4, 4]])
318
319
320
321    def test_setting_timestepping_method(self):
322        """test_set_quanitities_to_be_monitored
323        """
324
325        a = [0.0, 0.0]
326        b = [0.0, 2.0]
327        c = [2.0,0.0]
328        d = [0.0, 4.0]
329        e = [2.0, 2.0]
330        f = [4.0,0.0]
331
332        points = [a, b, c, d, e, f]
333        #bac, bce, ecf, dbe, daf, dae
334        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4]]
335
336
337        domain = Domain(points, vertices, boundary=None,
338                        conserved_quantities =\
339                        ['stage', 'xmomentum', 'ymomentum'],
340                        other_quantities = ['elevation', 'friction', 'depth'])
341
342
343        domain.timestepping_method = None
344
345
346        # Check that invalid requests are dealt with
347        try:
348            domain.set_timestepping_method('eee')       
349        except:
350            pass
351        else:
352            msg = 'Should have caught illegal method'
353            raise Exception, msg
354
355
356        #Should have no trouble with euler, rk2 or rk3
357        domain.set_timestepping_method('euler')
358        domain.set_timestepping_method('rk2')
359        domain.set_timestepping_method('rk3')
360
361        #test get timestepping method
362        assert domain.get_timestepping_method() == 'rk3'
363
364
365
366    def test_boundary_indices(self):
367
368        from anuga.config import default_boundary_tag
369
370
371        a = [0.0, 0.5]
372        b = [0.0, 0.0]
373        c = [0.5, 0.5]
374
375        points = [a, b, c]
376        vertices = [ [0,1,2] ]
377        domain = Domain(points, vertices)
378
379        domain.set_boundary( {default_boundary_tag: Dirichlet_boundary([5,2,1])} )
380
381
382        domain.check_integrity()
383
384        assert allclose(domain.neighbours, [[-1,-2,-3]])
385
386
387
388    def test_boundary_conditions(self):
389
390        a = [0.0, 0.0]
391        b = [0.0, 2.0]
392        c = [2.0,0.0]
393        d = [0.0, 4.0]
394        e = [2.0, 2.0]
395        f = [4.0,0.0]
396
397        points = [a, b, c, d, e, f]
398        #bac, bce, ecf, dbe
399        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4] ]
400        boundary = { (0, 0): 'First',
401                     (0, 2): 'First',
402                     (2, 0): 'Second',
403                     (2, 1): 'Second',
404                     (3, 1): 'Second',
405                     (3, 2): 'Second'}
406
407
408        domain = Domain(points, vertices, boundary,
409                        conserved_quantities =\
410                        ['stage', 'xmomentum', 'ymomentum'])
411        domain.check_integrity()
412
413
414
415        domain.set_quantity('stage', [[1,2,3], [5,5,5],
416                                      [0,0,9], [-6, 3, 3]])
417
418
419        domain.set_boundary( {'First': Dirichlet_boundary([5,2,1]),
420                              'Second': Transmissive_boundary(domain)} )
421
422        domain.update_boundary()
423
424        assert domain.quantities['stage'].boundary_values[0] == 5. #Dirichlet
425        assert domain.quantities['stage'].boundary_values[1] == 5. #Dirichlet
426        assert domain.quantities['stage'].boundary_values[2] ==\
427               domain.get_conserved_quantities(2, edge=0)[0] #Transmissive (4.5)
428        assert domain.quantities['stage'].boundary_values[3] ==\
429               domain.get_conserved_quantities(2, edge=1)[0] #Transmissive (4.5)
430        assert domain.quantities['stage'].boundary_values[4] ==\
431               domain.get_conserved_quantities(3, edge=1)[0] #Transmissive (-1.5)
432        assert domain.quantities['stage'].boundary_values[5] ==\
433               domain.get_conserved_quantities(3, edge=2)[0] #Transmissive (-1.5)
434
435        #Check enumeration
436        for k, ((vol_id, edge_id), _) in enumerate(domain.boundary_objects):
437            assert domain.neighbours[vol_id, edge_id] == -k-1
438
439
440
441
442    def test_distribute_first_order(self):
443        """Domain implements a default first order gradient limiter
444        """
445
446        a = [0.0, 0.0]
447        b = [0.0, 2.0]
448        c = [2.0,0.0]
449        d = [0.0, 4.0]
450        e = [2.0, 2.0]
451        f = [4.0,0.0]
452
453        points = [a, b, c, d, e, f]
454        #bac, bce, ecf, dbe
455        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4] ]
456        boundary = { (0, 0): 'Third',
457                     (0, 2): 'First',
458                     (2, 0): 'Second',
459                     (2, 1): 'Second',
460                     (3, 1): 'Second',
461                     (3, 2): 'Third'}
462
463
464        domain = Domain(points, vertices, boundary,
465                        conserved_quantities =\
466                        ['stage', 'xmomentum', 'ymomentum'])
467        domain.check_integrity()
468
469
470        domain.set_quantity('stage', [[1,2,3], [5,5,5],
471                                      [0,0,9], [-6, 3, 3]])
472
473        assert allclose( domain.quantities['stage'].centroid_values,
474                         [2,5,3,0] )
475
476        domain.set_quantity('xmomentum', [[1,1,1], [2,2,2],
477                                          [3,3,3], [4, 4, 4]])
478
479        domain.set_quantity('ymomentum', [[10,10,10], [20,20,20],
480                                          [30,30,30], [40, 40, 40]])
481
482
483        domain.distribute_to_vertices_and_edges()
484
485        #First order extrapolation
486        assert allclose( domain.quantities['stage'].vertex_values,
487                         [[ 2.,  2.,  2.],
488                          [ 5.,  5.,  5.],
489                          [ 3.,  3.,  3.],
490                          [ 0.,  0.,  0.]])
491
492
493
494
495    def test_update_conserved_quantities(self):
496        a = [0.0, 0.0]
497        b = [0.0, 2.0]
498        c = [2.0,0.0]
499        d = [0.0, 4.0]
500        e = [2.0, 2.0]
501        f = [4.0,0.0]
502
503        points = [a, b, c, d, e, f]
504        #bac, bce, ecf, dbe
505        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4] ]
506        boundary = { (0, 0): 'Third',
507                     (0, 2): 'First',
508                     (2, 0): 'Second',
509                     (2, 1): 'Second',
510                     (3, 1): 'Second',
511                     (3, 2): 'Third'}
512
513
514        domain = Domain(points, vertices, boundary,
515                        conserved_quantities =\
516                        ['stage', 'xmomentum', 'ymomentum'])
517        domain.check_integrity()
518
519
520        domain.set_quantity('stage', [1,2,3,4], location='centroids')
521        domain.set_quantity('xmomentum', [1,2,3,4], location='centroids')
522        domain.set_quantity('ymomentum', [1,2,3,4], location='centroids')
523
524
525        #Assign some values to update vectors
526        #Set explicit_update
527
528        for name in domain.conserved_quantities:
529            domain.quantities[name].explicit_update = array([4.,3.,2.,1.])
530            domain.quantities[name].semi_implicit_update = array([1.,1.,1.,1.])
531
532
533        #Update with given timestep (assuming no other forcing terms)
534        domain.timestep = 0.1
535        domain.update_conserved_quantities()
536
537        sem = array([1.,1.,1.,1.])/array([1, 2, 3, 4])
538        denom = ones(4, Float)-domain.timestep*sem
539
540#        x = array([1, 2, 3, 4]) + array( [.4,.3,.2,.1] )
541#        x /= denom
542
543        x = array([1., 2., 3., 4.])
544        x /= denom
545        x += domain.timestep*array( [4,3,2,1] )
546
547        for name in domain.conserved_quantities:
548            assert allclose(domain.quantities[name].centroid_values, x)
549
550
551    def test_set_region(self):
552        """Set quantities for sub region
553        """
554
555        a = [0.0, 0.0]
556        b = [0.0, 2.0]
557        c = [2.0,0.0]
558        d = [0.0, 4.0]
559        e = [2.0, 2.0]
560        f = [4.0,0.0]
561
562        points = [a, b, c, d, e, f]
563        #bac, bce, ecf, dbe
564        vertices = [ [1,0,2], [1,2,4], [4,2,5], [3,1,4] ]
565        boundary = { (0, 0): 'Third',
566                     (0, 2): 'First',
567                     (2, 0): 'Second',
568                     (2, 1): 'Second',
569                     (3, 1): 'Second',
570                     (3, 2): 'Third'}
571
572        domain = Domain(points, vertices, boundary,
573                        conserved_quantities =\
574                        ['stage', 'xmomentum', 'ymomentum'])
575        domain.check_integrity()
576
577        domain.set_quantity('stage', [[1,2,3], [5,5,5],
578                                      [0,0,9], [-6, 3, 3]])
579
580        assert allclose( domain.quantities['stage'].centroid_values,
581                         [2,5,3,0] )
582
583        domain.set_quantity('xmomentum', [[1,1,1], [2,2,2],
584                                          [3,3,3], [4, 4, 4]])
585
586        domain.set_quantity('ymomentum', [[10,10,10], [20,20,20],
587                                          [30,30,30], [40, 40, 40]])
588
589
590        domain.distribute_to_vertices_and_edges()
591
592        #First order extrapolation
593        assert allclose( domain.quantities['stage'].vertex_values,
594                         [[ 2.,  2.,  2.],
595                          [ 5.,  5.,  5.],
596                          [ 3.,  3.,  3.],
597                          [ 0.,  0.,  0.]])
598
599        domain.build_tagged_elements_dictionary({'mound':[0,1]})
600        domain.set_region([add_to_verts])
601
602        self.failUnless(domain.test == "Mound",
603                        'set region failed')
604
605
606    def test_track_speeds(self):
607        """
608        get values based on triangle lists.
609        """
610        from mesh_factory import rectangular
611        from shallow_water import Domain
612        from Numeric import zeros, Float
613
614        #Create basic mesh
615        points, vertices, boundary = rectangular(1, 3)
616
617        #Create shallow water domain
618        domain = Domain(points, vertices, boundary)
619        domain.timestepping_statistics(track_speeds=True)
620
621
622
623    def test_region_tags(self):
624        """
625        get values based on triangle lists.
626        """
627        from mesh_factory import rectangular
628        from shallow_water import Domain
629        from Numeric import zeros, Float
630
631        #Create basic mesh
632        points, vertices, boundary = rectangular(1, 3)
633
634        #Create shallow water domain
635        domain = Domain(points, vertices, boundary)
636        domain.build_tagged_elements_dictionary({'bottom':[0,1],
637                                                 'top':[4,5],
638                                                 'all':[0,1,2,3,4,5]})
639
640
641        #Set friction
642        manning = 0.07
643        domain.set_quantity('friction', manning)
644
645        domain.set_region([set_bottom_friction, set_top_friction])
646        #print domain.quantities['friction'].get_values()
647        assert allclose(domain.quantities['friction'].get_values(),\
648                        [[ 0.09,  0.09,  0.09],
649                         [ 0.09,  0.09,  0.09],
650                         [ 0.07,  0.07,  0.07],
651                         [ 0.07,  0.07,  0.07],
652                         [ 1.0,  1.0,  1.0],
653                         [ 1.0,  1.0,  1.0]])
654
655        domain.set_region([set_all_friction])
656        #print domain.quantities['friction'].get_values()
657        assert allclose(domain.quantities['friction'].get_values(),
658                        [[ 10.09, 10.09, 10.09],
659                         [ 10.09, 10.09, 10.09],
660                         [ 10.07, 10.07, 10.07],
661                         [ 10.07, 10.07, 10.07],
662                         [ 11.0,  11.0,  11.0],
663                         [ 11.0,  11.0,  11.0]])
664
665
666    def test_region_tags2(self):
667        """
668        get values based on triangle lists.
669        """
670        from mesh_factory import rectangular
671        from shallow_water import Domain
672        from Numeric import zeros, Float
673
674        #Create basic mesh
675        points, vertices, boundary = rectangular(1, 3)
676
677        #Create shallow water domain
678        domain = Domain(points, vertices, boundary)
679        domain.build_tagged_elements_dictionary({'bottom':[0,1],
680                                                 'top':[4,5],
681                                                 'all':[0,1,2,3,4,5]})
682
683
684        #Set friction
685        manning = 0.07
686        domain.set_quantity('friction', manning)
687
688        domain.set_region('top', 'friction', 1.0)
689        domain.set_region('bottom', 'friction', 0.09)
690       
691        #print domain.quantities['friction'].get_values()
692        assert allclose(domain.quantities['friction'].get_values(),\
693                        [[ 0.09,  0.09,  0.09],
694                         [ 0.09,  0.09,  0.09],
695                         [ 0.07,  0.07,  0.07],
696                         [ 0.07,  0.07,  0.07],
697                         [ 1.0,  1.0,  1.0],
698                         [ 1.0,  1.0,  1.0]])
699       
700        domain.set_region([set_bottom_friction, set_top_friction])
701        #print domain.quantities['friction'].get_values()
702        assert allclose(domain.quantities['friction'].get_values(),\
703                        [[ 0.09,  0.09,  0.09],
704                         [ 0.09,  0.09,  0.09],
705                         [ 0.07,  0.07,  0.07],
706                         [ 0.07,  0.07,  0.07],
707                         [ 1.0,  1.0,  1.0],
708                         [ 1.0,  1.0,  1.0]])
709
710        domain.set_region([set_all_friction])
711        #print domain.quantities['friction'].get_values()
712        assert allclose(domain.quantities['friction'].get_values(),
713                        [[ 10.09, 10.09, 10.09],
714                         [ 10.09, 10.09, 10.09],
715                         [ 10.07, 10.07, 10.07],
716                         [ 10.07, 10.07, 10.07],
717                         [ 11.0,  11.0,  11.0],
718                         [ 11.0,  11.0,  11.0]])
719
720#-------------------------------------------------------------
721if __name__ == "__main__":
722    suite = unittest.makeSuite(Test_Domain,'test')
723    #suite = unittest.makeSuite(Test_Domain,'test_track_speeds')
724    runner = unittest.TextTestRunner()
725    runner.run(suite)
Note: See TracBrowser for help on using the repository browser.