source: palm/trunk/SOURCE/lpm_init.f90 @ 1207

Last change on this file since 1207 was 1093, checked in by raasch, 12 years ago

last commit documented

  • Property svn:keywords set to Id
File size: 21.9 KB
Line 
1 SUBROUTINE lpm_init
2
3!--------------------------------------------------------------------------------!
4! This file is part of PALM.
5!
6! PALM is free software: you can redistribute it and/or modify it under the terms
7! of the GNU General Public License as published by the Free Software Foundation,
8! either version 3 of the License, or (at your option) any later version.
9!
10! PALM is distributed in the hope that it will be useful, but WITHOUT ANY
11! WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12! A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13!
14! You should have received a copy of the GNU General Public License along with
15! PALM. If not, see <http://www.gnu.org/licenses/>.
16!
17! Copyright 1997-2012  Leibniz University Hannover
18!--------------------------------------------------------------------------------!
19!
20! Current revisions:
21! -----------------
22!
23!
24! Former revisions:
25! -----------------
26! $Id: lpm_init.f90 1093 2013-02-02 12:58:49Z witha $
27!
28! 1092 2013-02-02 11:24:22Z raasch
29! unused variables removed
30!
31! 1036 2012-10-22 13:43:42Z raasch
32! code put under GPL (PALM 3.9)
33!
34! 849 2012-03-15 10:35:09Z raasch
35! routine renamed: init_particles -> lpm_init
36! de_dx, de_dy, de_dz are allocated here (instead of automatic arrays in
37! advec_particles),
38! sort_particles renamed lpm_sort_arrays, user_init_particles renamed lpm_init
39!
40! 828 2012-02-21 12:00:36Z raasch
41! call of init_kernels, particle feature color renamed class
42!
43! 824 2012-02-17 09:09:57Z raasch
44! particle attributes speed_x|y|z_sgs renamed rvar1|2|3,
45! array particles implemented as pointer
46!
47! 667 2010-12-23 12:06:00Z suehring/gryschka
48! nxl-1, nxr+1, nys-1, nyn+1 replaced by nxlg, nxrg, nysg, nyng for allocation
49! of arrays.
50!
51! 622 2010-12-10 08:08:13Z raasch
52! optional barriers included in order to speed up collective operations
53!
54! 336 2009-06-10 11:19:35Z raasch
55! Maximum number of tails is calculated from maximum number of particles and
56! skip_particles_for_tail,
57! output of messages replaced by message handling routine
58! Bugfix: arrays for tails are allocated with a minimum size of 10 tails if
59! there is no tail initially
60!
61! 150 2008-02-29 08:19:58Z raasch
62! Setting offset_ocean_* needed for calculating vertical indices within ocean
63! runs
64!
65! 117 2007-10-11 03:27:59Z raasch
66! Sorting of particles only in case of cloud droplets
67!
68! 106 2007-08-16 14:30:26Z raasch
69! variable iran replaced by iran_part
70!
71! 82 2007-04-16 15:40:52Z raasch
72! Preprocessor directives for old systems removed
73!
74! 70 2007-03-18 23:46:30Z raasch
75! displacements for mpi_particle_type changed, age_m initialized,
76! particles-package is now part of the default code
77!
78! 16 2007-02-15 13:16:47Z raasch
79! Bugfix: MPI_REAL in MPI_ALLREDUCE replaced by MPI_INTEGER
80!
81! r4 | raasch | 2007-02-13 12:33:16 +0100 (Tue, 13 Feb 2007)
82! RCS Log replace by Id keyword, revision history cleaned up
83!
84! Revision 1.24  2007/02/11 13:00:17  raasch
85! Bugfix: allocation of tail_mask and new_tail_id in case of restart-runs
86! Bugfix: __ was missing in a cpp-directive
87!
88! Revision 1.1  1999/11/25 16:22:38  raasch
89! Initial revision
90!
91!
92! Description:
93! ------------
94! This routine initializes a set of particles and their attributes (position,
95! radius, ..) which are used by the Lagrangian particle model (see lpm).
96!------------------------------------------------------------------------------!
97
98    USE arrays_3d
99    USE cloud_parameters
100    USE control_parameters
101    USE dvrp_variables
102    USE grid_variables
103    USE indices
104    USE lpm_collision_kernels_mod
105    USE particle_attributes
106    USE pegrid
107    USE random_function_mod
108
109
110    IMPLICIT NONE
111
112    INTEGER ::  i, j, n, nn
113#if defined( __parallel )
114    INTEGER, DIMENSION(3) ::  blocklengths, displacements, types
115#endif
116    LOGICAL ::  uniform_particles_l
117    REAL    ::  pos_x, pos_y, pos_z
118
119
120#if defined( __parallel )
121!
122!-- Define MPI derived datatype for FORTRAN datatype particle_type (see module
123!-- particle_attributes). Integer length is 4 byte, Real is 8 byte
124    blocklengths(1)  = 19;  blocklengths(2)  =   4;  blocklengths(3)  =   1
125    displacements(1) =  0;  displacements(2) = 152;  displacements(3) = 168
126
127    types(1) = MPI_REAL
128    types(2) = MPI_INTEGER
129    types(3) = MPI_UB
130    CALL MPI_TYPE_STRUCT( 3, blocklengths, displacements, types, &
131                          mpi_particle_type, ierr )
132    CALL MPI_TYPE_COMMIT( mpi_particle_type, ierr )
133#endif
134
135!
136!-- In case of oceans runs, the vertical index calculations need an offset,
137!-- because otherwise the k indices will become negative
138    IF ( ocean )  THEN
139       offset_ocean_nzt    = nzt
140       offset_ocean_nzt_m1 = nzt - 1
141    ENDIF
142
143
144!
145!-- Check the number of particle groups.
146    IF ( number_of_particle_groups > max_number_of_particle_groups )  THEN
147       WRITE( message_string, * ) 'max_number_of_particle_groups =',      &
148                                  max_number_of_particle_groups ,         &
149                                  '&number_of_particle_groups reset to ', &
150                                  max_number_of_particle_groups
151       CALL message( 'lpm_init', 'PA0213', 0, 1, 0, 6, 0 )
152       number_of_particle_groups = max_number_of_particle_groups
153    ENDIF
154
155!
156!-- Set default start positions, if necessary
157    IF ( psl(1) == 9999999.9 )  psl(1) = -0.5 * dx
158    IF ( psr(1) == 9999999.9 )  psr(1) = ( nx + 0.5 ) * dx
159    IF ( pss(1) == 9999999.9 )  pss(1) = -0.5 * dy
160    IF ( psn(1) == 9999999.9 )  psn(1) = ( ny + 0.5 ) * dy
161    IF ( psb(1) == 9999999.9 )  psb(1) = zu(nz/2)
162    IF ( pst(1) == 9999999.9 )  pst(1) = psb(1)
163
164    IF ( pdx(1) == 9999999.9  .OR.  pdx(1) == 0.0 )  pdx(1) = dx
165    IF ( pdy(1) == 9999999.9  .OR.  pdy(1) == 0.0 )  pdy(1) = dy
166    IF ( pdz(1) == 9999999.9  .OR.  pdz(1) == 0.0 )  pdz(1) = zu(2) - zu(1)
167
168    DO  j = 2, number_of_particle_groups
169       IF ( psl(j) == 9999999.9 )  psl(j) = psl(j-1)
170       IF ( psr(j) == 9999999.9 )  psr(j) = psr(j-1)
171       IF ( pss(j) == 9999999.9 )  pss(j) = pss(j-1)
172       IF ( psn(j) == 9999999.9 )  psn(j) = psn(j-1)
173       IF ( psb(j) == 9999999.9 )  psb(j) = psb(j-1)
174       IF ( pst(j) == 9999999.9 )  pst(j) = pst(j-1)
175       IF ( pdx(j) == 9999999.9  .OR.  pdx(j) == 0.0 )  pdx(j) = pdx(j-1)
176       IF ( pdy(j) == 9999999.9  .OR.  pdy(j) == 0.0 )  pdy(j) = pdy(j-1)
177       IF ( pdz(j) == 9999999.9  .OR.  pdz(j) == 0.0 )  pdz(j) = pdz(j-1)
178    ENDDO
179
180!
181!-- Allocate arrays required for calculating particle SGS velocities
182    IF ( use_sgs_for_particles )  THEN
183       ALLOCATE( de_dx(nzb:nzt+1,nysg:nyng,nxlg:nxrg), &
184                 de_dy(nzb:nzt+1,nysg:nyng,nxlg:nxrg), &
185                 de_dz(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
186    ENDIF
187
188!
189!-- Initialize collision kernels
190    IF ( collision_kernel /= 'none' )  CALL init_kernels
191
192!
193!-- For the first model run of a possible job chain initialize the
194!-- particles, otherwise read the particle data from restart file.
195    IF ( TRIM( initializing_actions ) == 'read_restart_data'  &
196         .AND.  read_particles_from_restartfile )  THEN
197
198       CALL lpm_read_restart_file
199
200    ELSE
201
202!
203!--    Allocate particle arrays and set attributes of the initial set of
204!--    particles, which can be also periodically released at later times.
205!--    Also allocate array for particle tail coordinates, if needed.
206       ALLOCATE( prt_count(nzb:nzt+1,nysg:nyng,nxlg:nxrg),       &
207                 prt_start_index(nzb:nzt+1,nysg:nyng,nxlg:nxrg), &
208                 particle_mask(maximum_number_of_particles),     &
209                 part_1(maximum_number_of_particles),            &
210                 part_2(maximum_number_of_particles)  )
211
212       particles => part_1
213
214       sort_count = 0
215
216!
217!--    Initialize all particles with dummy values (otherwise errors may
218!--    occur within restart runs). The reason for this is still not clear
219!--    and may be presumably caused by errors in the respective user-interface.
220       particles = particle_type( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, &
221                                  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, &
222                                  0.0, 0, 0, 0, 0 )
223       particle_groups = particle_groups_type( 0.0, 0.0, 0.0, 0.0 )
224
225!
226!--    Set the default particle size used for dvrp plots
227       IF ( dvrp_psize == 9999999.9 )  dvrp_psize = 0.2 * dx
228
229!
230!--    Set values for the density ratio and radius for all particle
231!--    groups, if necessary
232       IF ( density_ratio(1) == 9999999.9 )  density_ratio(1) = 0.0
233       IF ( radius(1)        == 9999999.9 )  radius(1) = 0.0
234       DO  i = 2, number_of_particle_groups
235          IF ( density_ratio(i) == 9999999.9 )  THEN
236             density_ratio(i) = density_ratio(i-1)
237          ENDIF
238          IF ( radius(i) == 9999999.9 )  radius(i) = radius(i-1)
239       ENDDO
240
241       DO  i = 1, number_of_particle_groups
242          IF ( density_ratio(i) /= 0.0  .AND.  radius(i) == 0 )  THEN
243             WRITE( message_string, * ) 'particle group #', i, 'has a', &
244                                        'density ratio /= 0 but radius = 0'
245             CALL message( 'lpm_init', 'PA0215', 1, 2, 0, 6, 0 )
246          ENDIF
247          particle_groups(i)%density_ratio = density_ratio(i)
248          particle_groups(i)%radius        = radius(i)
249       ENDDO
250
251!
252!--    Calculate particle positions and store particle attributes, if
253!--    particle is situated on this PE
254       n = 0
255
256       DO  i = 1, number_of_particle_groups
257
258          pos_z = psb(i)
259
260          DO WHILE ( pos_z <= pst(i) )
261
262             pos_y = pss(i)
263
264             DO WHILE ( pos_y <= psn(i) )
265
266                IF ( pos_y >= ( nys - 0.5 ) * dy  .AND.  &
267                     pos_y <  ( nyn + 0.5 ) * dy )  THEN
268
269                   pos_x = psl(i)
270
271                   DO WHILE ( pos_x <= psr(i) )
272
273                      IF ( pos_x >= ( nxl - 0.5 ) * dx  .AND.  &
274                           pos_x <  ( nxr + 0.5 ) * dx )  THEN
275
276                         DO  j = 1, particles_per_point
277
278                            n = n + 1
279                            IF ( n > maximum_number_of_particles )  THEN
280                               WRITE( message_string, * ) 'number of initial', &
281                                      'particles (', n, ') exceeds',           &
282                                      '&maximum_number_of_particles (',        &
283                                      maximum_number_of_particles, ') on PE ', &
284                                             myid
285                               CALL message( 'lpm_init', 'PA0216', 2, 2, -1, 6,&
286                                             1 )
287                            ENDIF
288                            particles(n)%x             = pos_x
289                            particles(n)%y             = pos_y
290                            particles(n)%z             = pos_z
291                            particles(n)%age           = 0.0
292                            particles(n)%age_m         = 0.0
293                            particles(n)%dt_sum        = 0.0
294                            particles(n)%dvrp_psize    = dvrp_psize
295                            particles(n)%e_m           = 0.0
296                            IF ( curvature_solution_effects )  THEN
297!
298!--                            Initial values (internal timesteps, derivative)
299!--                            for Rosenbrock method
300                               particles(n)%rvar1      = 1.0E-12
301                               particles(n)%rvar2      = 1.0E-3
302                               particles(n)%rvar3      = -9999999.9
303                            ELSE
304!
305!--                            Initial values for SGS velocities
306                               particles(n)%rvar1      = 0.0
307                               particles(n)%rvar2      = 0.0
308                               particles(n)%rvar3      = 0.0
309                            ENDIF
310                            particles(n)%speed_x       = 0.0
311                            particles(n)%speed_y       = 0.0
312                            particles(n)%speed_z       = 0.0
313                            particles(n)%origin_x      = pos_x
314                            particles(n)%origin_y      = pos_y
315                            particles(n)%origin_z      = pos_z
316                            particles(n)%radius      = particle_groups(i)%radius
317                            particles(n)%weight_factor =initial_weighting_factor
318                            particles(n)%class         = 1
319                            particles(n)%group         = i
320                            particles(n)%tailpoints    = 0
321                            IF ( use_particle_tails  .AND. &
322                                 MOD( n, skip_particles_for_tail ) == 0 )  THEN
323                               number_of_tails         = number_of_tails + 1
324!
325!--                            This is a temporary provisional setting (see
326!--                            further below!)
327                               particles(n)%tail_id    = number_of_tails
328                            ELSE
329                               particles(n)%tail_id    = 0
330                            ENDIF
331
332                         ENDDO
333
334                      ENDIF
335
336                      pos_x = pos_x + pdx(i)
337
338                   ENDDO
339
340                ENDIF
341
342                pos_y = pos_y + pdy(i)
343
344             ENDDO
345
346             pos_z = pos_z + pdz(i)
347
348          ENDDO
349
350       ENDDO
351
352       number_of_initial_particles = n
353       number_of_particles         = n
354
355!
356!--    Calculate the number of particles and tails of the total domain
357#if defined( __parallel )
358       IF ( collective_wait )  CALL MPI_BARRIER( comm2d, ierr )
359       CALL MPI_ALLREDUCE( number_of_particles, total_number_of_particles, 1, &
360                           MPI_INTEGER, MPI_SUM, comm2d, ierr )
361       IF ( collective_wait )  CALL MPI_BARRIER( comm2d, ierr )
362       CALL MPI_ALLREDUCE( number_of_tails, total_number_of_tails, 1, &
363                           MPI_INTEGER, MPI_SUM, comm2d, ierr )
364#else
365       total_number_of_particles = number_of_particles
366       total_number_of_tails     = number_of_tails
367#endif
368
369!
370!--    Set a seed value for the random number generator to be exclusively
371!--    used for the particle code. The generated random numbers should be
372!--    different on the different PEs.
373       iran_part = iran_part + myid
374
375!
376!--    User modification of initial particles
377       CALL user_lpm_init
378
379!
380!--    Store the initial set of particles for release at later times
381       IF ( number_of_initial_particles /= 0 )  THEN
382          ALLOCATE( initial_particles(1:number_of_initial_particles) )
383          initial_particles(1:number_of_initial_particles) = &
384                                        particles(1:number_of_initial_particles)
385       ENDIF
386
387!
388!--    Add random fluctuation to particle positions
389       IF ( random_start_position )  THEN
390
391          DO  n = 1, number_of_initial_particles
392             IF ( psl(particles(n)%group) /= psr(particles(n)%group) )  THEN
393                particles(n)%x = particles(n)%x + &
394                                 ( random_function( iran_part ) - 0.5 ) * &
395                                 pdx(particles(n)%group)
396                IF ( particles(n)%x  <=  ( nxl - 0.5 ) * dx )  THEN
397                   particles(n)%x = ( nxl - 0.4999999999 ) * dx
398                ELSEIF ( particles(n)%x  >=  ( nxr + 0.5 ) * dx )  THEN
399                   particles(n)%x = ( nxr + 0.4999999999 ) * dx
400                ENDIF
401             ENDIF
402             IF ( pss(particles(n)%group) /= psn(particles(n)%group) )  THEN
403                particles(n)%y = particles(n)%y + &
404                                 ( random_function( iran_part ) - 0.5 ) * &
405                                 pdy(particles(n)%group)
406                IF ( particles(n)%y  <=  ( nys - 0.5 ) * dy )  THEN
407                   particles(n)%y = ( nys - 0.4999999999 ) * dy
408                ELSEIF ( particles(n)%y  >=  ( nyn + 0.5 ) * dy )  THEN
409                   particles(n)%y = ( nyn + 0.4999999999 ) * dy
410                ENDIF
411             ENDIF
412             IF ( psb(particles(n)%group) /= pst(particles(n)%group) )  THEN
413                particles(n)%z = particles(n)%z + &
414                                 ( random_function( iran_part ) - 0.5 ) * &
415                                 pdz(particles(n)%group)
416             ENDIF
417          ENDDO
418       ENDIF
419
420!
421!--    Sort particles in the sequence the gridboxes are stored in the memory.
422!--    Only required if cloud droplets are used.
423       IF ( cloud_droplets )  CALL lpm_sort_arrays
424
425!
426!--    Open file for statistical informations about particle conditions
427       IF ( write_particle_statistics )  THEN
428          CALL check_open( 80 )
429          WRITE ( 80, 8000 )  current_timestep_number, simulated_time, &
430                              number_of_initial_particles,             &
431                              maximum_number_of_particles
432          CALL close_file( 80 )
433       ENDIF
434
435!
436!--    Check if particles are really uniform in color and radius (dvrp_size)
437!--    (uniform_particles is preset TRUE)
438       IF ( uniform_particles )  THEN
439          IF ( number_of_initial_particles == 0 )  THEN
440             uniform_particles_l = .TRUE.
441          ELSE
442             n = number_of_initial_particles
443             IF ( MINVAL( particles(1:n)%dvrp_psize  ) ==     &
444                  MAXVAL( particles(1:n)%dvrp_psize  )  .AND. &
445                  MINVAL( particles(1:n)%class ) ==     &
446                  MAXVAL( particles(1:n)%class ) )  THEN
447                uniform_particles_l = .TRUE.
448             ELSE
449                uniform_particles_l = .FALSE.
450             ENDIF
451          ENDIF
452
453#if defined( __parallel )
454          IF ( collective_wait )  CALL MPI_BARRIER( comm2d, ierr )
455          CALL MPI_ALLREDUCE( uniform_particles_l, uniform_particles, 1, &
456                              MPI_LOGICAL, MPI_LAND, comm2d, ierr )
457#else
458          uniform_particles = uniform_particles_l
459#endif
460
461       ENDIF
462
463!
464!--    Particles will probably become none-uniform, if their size and color
465!--    will be determined by flow variables
466       IF ( particle_color /= 'none'  .OR.  particle_dvrpsize /= 'none' )  THEN
467          uniform_particles = .FALSE.
468       ENDIF
469
470!
471!--    Set the beginning of the particle tails and their age
472       IF ( use_particle_tails )  THEN
473!
474!--       Choose the maximum number of tails with respect to the maximum number
475!--       of particles and skip_particles_for_tail
476          maximum_number_of_tails = maximum_number_of_particles / &
477                                    skip_particles_for_tail
478
479!
480!--       Create a minimum number of tails in case that there is no tail
481!--       initially (otherwise, index errors will occur when adressing the
482!--       arrays below)
483          IF ( maximum_number_of_tails == 0 )  maximum_number_of_tails = 10
484
485          ALLOCATE( particle_tail_coordinates(maximum_number_of_tailpoints,5, &
486                    maximum_number_of_tails),                                 &
487                    new_tail_id(maximum_number_of_tails),                     &
488                    tail_mask(maximum_number_of_tails) )
489
490          particle_tail_coordinates  = 0.0
491          minimum_tailpoint_distance = minimum_tailpoint_distance**2
492          number_of_initial_tails    = number_of_tails
493
494          nn = 0
495          DO  n = 1, number_of_particles
496!
497!--          Only for those particles marked above with a provisional tail_id
498!--          tails will be created. Particles now get their final tail_id.
499             IF ( particles(n)%tail_id /= 0 )  THEN
500
501                nn = nn + 1
502                particles(n)%tail_id = nn
503
504                particle_tail_coordinates(1,1,nn) = particles(n)%x
505                particle_tail_coordinates(1,2,nn) = particles(n)%y
506                particle_tail_coordinates(1,3,nn) = particles(n)%z
507                particle_tail_coordinates(1,4,nn) = particles(n)%class
508                particles(n)%tailpoints = 1
509                IF ( minimum_tailpoint_distance /= 0.0 )  THEN
510                   particle_tail_coordinates(2,1,nn) = particles(n)%x
511                   particle_tail_coordinates(2,2,nn) = particles(n)%y
512                   particle_tail_coordinates(2,3,nn) = particles(n)%z
513                   particle_tail_coordinates(2,4,nn) = particles(n)%class
514                   particle_tail_coordinates(1:2,5,nn) = 0.0
515                   particles(n)%tailpoints = 2
516                ENDIF
517
518             ENDIF
519          ENDDO
520       ENDIF
521
522!
523!--    Plot initial positions of particles (only if particle advection is
524!--    switched on from the beginning of the simulation (t=0))
525       IF ( particle_advection_start == 0.0 )  CALL data_output_dvrp
526
527    ENDIF
528
529!
530!-- Check boundary condition and set internal variables
531    SELECT CASE ( bc_par_b )
532   
533       CASE ( 'absorb' )
534          ibc_par_b = 1
535
536       CASE ( 'reflect' )
537          ibc_par_b = 2
538         
539       CASE DEFAULT
540          WRITE( message_string, * )  'unknown boundary condition ',   &
541                                       'bc_par_b = "', TRIM( bc_par_b ), '"'
542          CALL message( 'lpm_init', 'PA0217', 1, 2, 0, 6, 0 )
543         
544    END SELECT
545    SELECT CASE ( bc_par_t )
546   
547       CASE ( 'absorb' )
548          ibc_par_t = 1
549
550       CASE ( 'reflect' )
551          ibc_par_t = 2
552         
553       CASE DEFAULT
554          WRITE( message_string, * ) 'unknown boundary condition ',   &
555                                     'bc_par_t = "', TRIM( bc_par_t ), '"'
556          CALL message( 'lpm_init', 'PA0218', 1, 2, 0, 6, 0 )
557         
558    END SELECT
559    SELECT CASE ( bc_par_lr )
560
561       CASE ( 'cyclic' )
562          ibc_par_lr = 0
563
564       CASE ( 'absorb' )
565          ibc_par_lr = 1
566
567       CASE ( 'reflect' )
568          ibc_par_lr = 2
569         
570       CASE DEFAULT
571          WRITE( message_string, * ) 'unknown boundary condition ',   &
572                                     'bc_par_lr = "', TRIM( bc_par_lr ), '"'
573          CALL message( 'lpm_init', 'PA0219', 1, 2, 0, 6, 0 )
574         
575    END SELECT
576    SELECT CASE ( bc_par_ns )
577
578       CASE ( 'cyclic' )
579          ibc_par_ns = 0
580
581       CASE ( 'absorb' )
582          ibc_par_ns = 1
583
584       CASE ( 'reflect' )
585          ibc_par_ns = 2
586         
587       CASE DEFAULT
588          WRITE( message_string, * ) 'unknown boundary condition ',   &
589                                     'bc_par_ns = "', TRIM( bc_par_ns ), '"'
590          CALL message( 'lpm_init', 'PA0220', 1, 2, 0, 6, 0 )
591         
592    END SELECT
593!
594!-- Formats
5958000 FORMAT (I6,1X,F7.2,4X,I6,71X,I6)
596
597 END SUBROUTINE lpm_init
Note: See TracBrowser for help on using the repository browser.