OpenFPM_pdata  1.1.0
Project that contain the implementation of distributed structures
 All Data Structures Namespaces Functions Variables Typedefs Enumerations Friends Pages
VerletListFast.hpp
1 /*
2  * VerletListFast.hpp
3  *
4  * Created on: Aug 16, 2016
5  * Author: i-bird
6  */
7 
8 #ifndef OPENFPM_DATA_SRC_NN_VERLETLIST_VERLETLISTFAST_HPP_
9 #define OPENFPM_DATA_SRC_NN_VERLETLIST_VERLETLISTFAST_HPP_
10 
11 #include "VerletNNIterator.hpp"
12 #include "NN/CellList/CellList_util.hpp"
13 #include "NN/Mem_type/MemFast.hpp"
14 #include "NN/Mem_type/MemBalanced.hpp"
15 #include "NN/Mem_type/MemMemoryWise.hpp"
16 
17 #define VERLET_STARTING_NSLOT 128
18 
19 
20 #define WITH_RADIUS 3
21 
31 template<unsigned int dim, typename T, typename CellListImpl, typename PartIt, int type, typename local_index>
32 struct NNType
33 {
45  static inline auto get(const PartIt & it,
47  Point<dim,T> & xp,
48  size_t p,
49  CellListImpl & cl,
50  T r_cut) -> decltype(cl.template getNNIterator<NO_CHECK>(0))
51  {
52  return cl.template getNNIterator<NO_CHECK>(cl.getCell(xp));
53  }
54 
61  static inline void add(local_index p, openfpm::vector<local_index> & pc)
62  {
63  }
64 };
65 
66 
77 template<unsigned int dim, typename T, typename CellListImpl, typename PartIt, typename local_index>
78 struct NNType<dim,T,CellListImpl,PartIt,WITH_RADIUS,local_index>
79 {
91  static inline auto get(const PartIt & it,
93  Point<dim,T> & xp,
94  size_t p,
95  CellListImpl & cl,
96  T r_cut) -> decltype(cl.template getNNIteratorRadius<NO_CHECK>(0,0.0))
97  {
98  return cl.template getNNIteratorRadius<NO_CHECK>(cl.getCell(xp),r_cut);
99  }
100 
107  static inline void add(local_index p, openfpm::vector<local_index> & pc)
108  {
109  }
110 };
111 
112 
123 template<unsigned int dim, typename T, typename CellListImpl, typename PartIt, typename local_index>
124 struct NNType<dim,T,CellListImpl,PartIt,VL_SYMMETRIC,local_index>
125 {
137  static inline auto get(const PartIt & it, const openfpm::vector<Point<dim,T>> & v, Point<dim,T> & xp, size_t p, CellListImpl & cl, T r_cut) -> decltype(cl.template getNNIteratorSym<NO_CHECK>(0,0,openfpm::vector<Point<dim,T>>()))
138  {
139  return cl.template getNNIteratorSym<NO_CHECK>(cl.getCell(xp),p,v);
140  }
141 
148  static inline void add(local_index p, openfpm::vector<local_index> & pc)
149  {
150  }
151 };
152 
153 
164 template<unsigned int dim, typename T, typename CellListImpl, typename PartIt, typename local_index>
165 struct NNType<dim,T,CellListImpl,PartIt,VL_CRS_SYMMETRIC,local_index>
166 {
179  static inline auto get(const PartIt & it,const openfpm::vector<Point<dim,T>> & v, Point<dim,T> & xp, size_t p, CellListImpl & cl, T r_cut) -> decltype(it.getNNIteratorCSR(v))
180  {
181  return it.getNNIteratorCSR(v);
182  }
183 
190  static inline void add(local_index p, openfpm::vector<local_index> & pc)
191  {
192  pc.add(p);
193  }
194 };
195 
202 template<unsigned int type, unsigned int dim, typename vector, typename CellList>
203 class PartItNN
204 {
205 public:
206 
219  static inline auto get(const vector & pos, const openfpm::vector<size_t> & dom, const openfpm::vector<subsub_lin<dim>> & anom, CellList & cli, size_t g_m, size_t & end) -> decltype(pos.getIteratorTo(0))
220  {
221  end = g_m;
222  return pos.getIteratorTo(end);
223  }
224 };
225 
232 template<unsigned int dim, typename vector, typename CellList>
233 class PartItNN<VL_CRS_SYMMETRIC,dim,vector,CellList>
234 {
235 public:
236 
249  static inline ParticleItCRS_Cells<dim,CellList> get(const vector & pos, const openfpm::vector<size_t> & dom, const openfpm::vector<subsub_lin<dim>> & anom, CellList & cli, size_t g_m, size_t & end)
250  {
251  end = pos.size();
252  return ParticleItCRS_Cells<dim,CellList>(cli,dom,anom,cli.getNNc_sym());
253  }
254 };
255 
275 template<unsigned int dim,
276  typename T,
277  typename Mem_type = Mem_fast<local_index_>,
278  typename transform = no_transform<dim,T>,
279  typename CellListImpl = CellList<dim,T,Mem_fast<typename Mem_type::loc_index>,transform> >
280 class VerletList: public Mem_type
281 {
282 protected:
283 
285  typename Mem_type::loc_index slot;
286 
289 
290 private:
291 
293  size_t n_dec;
294 
296  CellListImpl cli;
297 
298 
307  void initCl(CellListImpl & cli, openfpm::vector<Point<dim,T>> & pos, size_t g_m, size_t opt)
308  {
309  if (opt & VL_SYMMETRIC || opt & VL_CRS_SYMMETRIC)
310  populate_cell_list(pos,cli,g_m,CL_SYMMETRIC);
311  else
312  populate_cell_list(pos,cli,g_m,CL_NON_SYMMETRIC);
313  }
314 
327  inline void create(const openfpm::vector<Point<dim,T>> & pos, const openfpm::vector<Point<dim,T>> & pos2, const openfpm::vector<size_t> & dom, const openfpm::vector<subsub_lin<dim>> & anom, T r_cut, size_t g_m, CellListImpl & cl, size_t opt)
328  {
329  if (opt == VL_CRS_SYMMETRIC)
330  {
331  create_<CellNNIteratorSym<dim,CellListImpl,RUNTIME,NO_CHECK>,VL_CRS_SYMMETRIC>(pos,pos2,dom,anom,r_cut,g_m,cl,opt);
332  }
333  else if (opt == VL_SYMMETRIC)
334  {
335  create_<decltype(cl.template getNNIteratorSym<NO_CHECK>(0,0,pos)),VL_SYMMETRIC>(pos,pos2,dom,anom,r_cut,g_m,cl,opt);
336  }
337  else
338  {
339  create_<decltype(cl.template getNNIterator<NO_CHECK>(0)),VL_NON_SYMMETRIC>(pos,pos2,dom,anom,r_cut,g_m,cl,opt);
340  }
341  }
342 
357  template<typename NN_type, int type> inline void create_(const openfpm::vector<Point<dim,T>> & pos, const openfpm::vector<Point<dim,T>> & pos2 , const openfpm::vector<size_t> & dom, const openfpm::vector<subsub_lin<dim>> & anom, T r_cut, size_t g_m, CellListImpl & cli, size_t opt)
358  {
359  size_t end;
360 
361  auto it = PartItNN<type,dim,openfpm::vector<Point<dim,T>>,CellListImpl>::get(pos,dom,anom,cli,g_m,end);
362 
363  Mem_type::init_to_zero(slot,end);
364 
365  dp.clear();
366 
367  // square of the cutting radius
368  T r_cut2 = r_cut * r_cut;
369 
370  // iterate the particles
371  while (it.isNext())
372  {
373  typename Mem_type::loc_index i = it.get();
374  Point<dim,T> xp = pos.template get<0>(i);
375 
376  // Get the neighborhood of the particle
379 
380  while (NN.isNext())
381  {
382  auto nnp = NN.get();
383 
384  Point<dim,T> xq = pos2.template get<0>(nnp);
385 
386  if (xp.distance2(xq) < r_cut2)
387  addPart(i,nnp);
388 
389  // Next particle
390  ++NN;
391  }
392 
393  ++it;
394  }
395  }
396 
407  inline void createR(openfpm::vector<Point<dim,T>> & pos, T r_cut, size_t g_m, CellListImpl & cl)
408  {
409 
410  Mem_type::init_to_zero(slot,g_m);
411 
412  // square of the cutting radius
413  T r_cut2 = r_cut * r_cut;
414 
415  // iterate the particles
416  for (size_t i = 0 ; i < g_m ; i++)
417  {
418  Point<dim,T> p = pos.template get<0>(i);
419 
420  // Get the neighborhood of the particle
421  auto NN = cl.template getNNIteratorRadius<NO_CHECK>(cl.getCell(p),r_cut);
422  while (NN.isNext())
423  {
424  auto nnp = NN.get();
425 
426  Point<dim,T> q = pos.template get<0>(nnp);
427 
428  if (p.distance2(q) < r_cut2)
429  addPart(i,nnp);
430 
431  // Next particle
432  ++NN;
433  }
434  }
435  }
436 
437 public:
438 
440  typedef Mem_type Mem_type_type;
441 
443  typedef size_t value_type;
444 
446  typedef CellListImpl CellListImpl_;
447 
453  size_t size()
454  {
455  return Mem_type::size();
456  }
457 
464  inline void addPart(size_t part_id, size_t ele)
465  {
466  Mem_type::addCell(part_id,ele);
467  }
468 
481  void Initialize(const Box<dim,T> & box, const Box<dim,T> & dom, T r_cut, openfpm::vector<Point<dim,T>> & pos, size_t g_m, size_t opt = VL_NON_SYMMETRIC)
482  {
483  // Number of divisions
484  size_t div[dim];
485 
486  Box<dim,T> bt = box;
487 
488  // Calculate the divisions for the Cell-lists
489  cl_param_calculate(bt,div,r_cut,Ghost<dim,T>(0.0));
490 
491  // Initialize a cell-list
492  cli.Initialize(bt,div);
493  initCl(cli,pos,g_m,opt);
494 
495  // Unuseful empty vector
498 
499  // create verlet
500  create(pos, pos,dom_c,anom_c,r_cut,g_m,cli,opt);
501  }
502 
515  void InitializeSym(const Box<dim,T> & box, const Box<dim,T> & dom, const Ghost<dim,T> & g, T r_cut, openfpm::vector<Point<dim,T>> & pos, size_t g_m)
516  {
517  // Padding
518  size_t pad = 0;
519 
520  // Cell decomposer
521  CellDecomposer_sm<dim,T,shift<dim,T>> cd_sm;
522 
523  // Calculate the divisions for the Cell-lists
524  cl_param_calculateSym<dim,T>(box,cd_sm,g,r_cut,pad);
525 
526  // Initialize a cell-list
527  cli.Initialize(cd_sm,dom,pad);
528  initCl(cli,pos,g_m,VL_SYMMETRIC);
529 
530  // Unused
533 
534  // create verlet
535  create(pos, pos,dom_c,anom_c,r_cut,g_m,cli,VL_SYMMETRIC);
536  }
537 
538 
551  void InitializeCrs(const Box<dim,T> & box, const Box<dim,T> & dom, const Ghost<dim,T> & g, T r_cut, openfpm::vector<Point<dim,T>> & pos, size_t g_m)
552  {
553  // Padding
554  size_t pad = 0;
555 
556  // Cell decomposer
557  CellDecomposer_sm<dim,T,shift<dim,T>> cd_sm;
558 
559  // Calculate the divisions for the Cell-lists
560  cl_param_calculateSym<dim,T>(box,cd_sm,g,r_cut,pad);
561 
562  // Initialize a cell-list
563  cli.Initialize(cd_sm,dom,pad);
564  initCl(cli,pos,g_m,VL_SYMMETRIC);
565  }
566 
578  {
579  // create verlet
580  create(pos, pos,dom_c,anom_c,r_cut,g_m,cli,VL_CRS_SYMMETRIC);
581  }
582 
592  void update(const Box<dim,T> & dom, T r_cut, openfpm::vector<Point<dim,T>> & pos, size_t & g_m, size_t opt)
593  {
594  initCl(cli,pos,g_m,opt);
595 
596  // Unused
599 
600  create(pos, pos,dom_c,anom_c,r_cut,g_m,cli,opt);
601  }
602 
613  void updateCrs(const Box<dim,T> & dom, T r_cut, openfpm::vector<Point<dim,T>> & pos, size_t & g_m, const openfpm::vector<size_t> & dom_c, const openfpm::vector<subsub_lin<dim>> & anom_c)
614  {
615  initCl(cli,pos,g_m,VL_CRS_SYMMETRIC);
616 
617  create(pos,pos,dom_c,anom_c,r_cut,g_m,cli,VL_CRS_SYMMETRIC);
618  }
619 
632  void Initialize(CellListImpl & cli,
633  T r_cut,
634  const openfpm::vector<Point<dim,T>> & pos,
635  const openfpm::vector<Point<dim,T>> & pos2,
636  size_t g_m, size_t opt = VL_NON_SYMMETRIC)
637  {
638  Point<dim,T> spacing = cli.getCellBox().getP2();
639 
640  // Create with radius or not
641  bool wr = true;
642 
643  for (size_t i = 0 ; i < dim ; i++)
644  wr &= r_cut <= spacing.get(i);
645 
646  if (wr == true || opt == VL_SYMMETRIC)
647  {
650 
651  create(pos,pos2,dom_c,anom_c,r_cut,g_m,cli,opt);
652  }
653  else
654  {
657 
658  create_<decltype(cli.template getNNIteratorRadius<NO_CHECK>(0,0.0)),WITH_RADIUS>(pos,pos2,dom_c,anom_c,r_cut,g_m,cli,VL_NON_SYMMETRIC);
659  }
660  }
661 
664  :Mem_type(VERLET_STARTING_NSLOT),slot(VERLET_STARTING_NSLOT),n_dec(0)
665  {};
666 
669  :Mem_type(VERLET_STARTING_NSLOT),slot(VERLET_STARTING_NSLOT)
670  {
671  this->operator=(cell);
672  }
673 
676  :Mem_type(VERLET_STARTING_NSLOT),slot(VERLET_STARTING_NSLOT),n_dec(0)
677  {
678  this->operator=(cell);
679  }
680 
681 
691  VerletList(Box<dim,T> & box, T r_cut, Matrix<dim,T> mat, const size_t pad = 1, size_t slot=STARTING_NSLOT)
692  :slot(VERLET_STARTING_NSLOT),CellDecomposer_sm<dim,T,transform>(box,div,mat,box.getP1(),pad)
693  {
694  SpaceBox<dim,T> sbox(box);
695  Initialize(sbox,r_cut,pad,slot);
696  }
697 
711  VerletList(Box<dim,T> & box, T r_cut, openfpm::vector<Point<dim,T>> & pos, size_t g_m, size_t slot=VERLET_STARTING_NSLOT)
712  :slot(slot)
713  {
714  SpaceBox<dim,T> sbox(box);
715  Initialize(sbox,r_cut,pos,g_m);
716  }
717 
732  VerletList(SpaceBox<dim,T> & box, Box<dim,T> & dom, T r_cut, openfpm::vector<Point<dim,T>> & pos, size_t g_m, size_t slot=VERLET_STARTING_NSLOT)
733  :slot(slot)
734  {
735  Initialize(box,r_cut,pos);
736  }
737 
743  {}
744 
754  {
755  slot = vl.slot;
756 
757  Mem_type::operator=(vl);
758  dp.swap(vl.dp);
759 
760  n_dec = vl.n_dec;
761 
762  return *this;
763  }
764 
773  {
774  slot = vl.slot;
775 
776  Mem_type::operator=(vl);
777 
778  cli = vl.cli;
779 
780  dp = vl.dp;
781  n_dec = vl.n_dec;
782 
783  return *this;
784  }
785 
793  inline size_t getNNPart(size_t part_id) const
794  {
795  return Mem_type::getNelements(part_id);
796  }
797 
806  inline size_t get(size_t i, size_t j) const
807  {
808  return Mem_type::get(i,j);
809  }
810 
817  {
818  Mem_type::swap(vl);
819  dp.swap(vl.dp);
820 
821  size_t vl_slot_tmp = vl.slot;
822  vl.slot = slot;
823  slot = vl_slot_tmp;
824 
825  cli.swap(vl.cli);
826 
827  size_t n_dec_tmp = vl.n_dec;
828  vl.n_dec = n_dec;
829  n_dec = n_dec_tmp;
830  }
831 
841  template<unsigned int impl=NO_CHECK>
843  getNNIterator(size_t part_id)
844  {
846 
847  return vln;
848  }
849 
853  void clear()
854  {
855  Mem_type::clear();
856  }
857 
865  inline const typename Mem_type::loc_index &
866  getStart(typename Mem_type::loc_index part_id)
867  {
868  return Mem_type::getStartId(part_id);
869  }
870 
878  inline const typename Mem_type::loc_index &
879  getStop(typename Mem_type::loc_index part_id)
880  {
881  return Mem_type::getStopId(part_id);
882  }
883 
891  inline const typename Mem_type::loc_index &
892  get_lin(const typename Mem_type::loc_index * part_id)
893  {
894  return Mem_type::get_lin(part_id);
895  }
896 
902  CellListImpl & getInternalCellList()
903  {
904  return cli;
905  }
906 
912  void set_ndec(size_t n_dec)
913  {
914  this->n_dec = n_dec;
915 
916  cli.set_ndec(n_dec);
917  }
918 
924  size_t get_ndec()
925  {
926  return n_dec;
927  }
928 
935  {
936  return dp;
937  }
938 };
939 
940 
941 
942 #endif /* OPENFPM_DATA_SRC_NN_VERLETLIST_VERLETLISTFAST_HPP_ */
openfpm::vector< typename Mem_type::loc_index > dp
Domain particles.
VerletList(const VerletList< dim, T, Mem_type, transform, CellListImpl > &cell)
Copy constructor.
This class represent an N-dimensional box.
Definition: SpaceBox.hpp:26
VerletList(Box< dim, T > &box, T r_cut, Matrix< dim, T > mat, const size_t pad=1, size_t slot=STARTING_NSLOT)
Verlet-list constructor.
size_t get(size_t i, size_t j) const
Get the neighborhood element j for the particle i.
const Mem_type::loc_index & getStart(typename Mem_type::loc_index part_id)
Return the starting point of the neighborhood for the particle p.
void createR(openfpm::vector< Point< dim, T >> &pos, T r_cut, size_t g_m, CellListImpl &cl)
Create the Verlet list from a given cell-list with a particular cut-off radius.
Class for Verlet list implementation.
No transformation.
size_t value_type
Object type that the structure store.
void createVerletCrs(T r_cut, size_t g_m, openfpm::vector< Point< dim, T >> &pos, openfpm::vector< size_t > &dom_c, openfpm::vector< subsub_lin< dim >> &anom_c)
Create the Verlet-list with the crossing scheme.
static void add(local_index p, openfpm::vector< local_index > &pc)
Add particle in the list of the domain particles.
It is a class that work like a vector of vector.
Definition: MemFast.hpp:30
size_t n_dec
decomposition counter
This class implement the point shape in an N-dimensional space.
Definition: Point.hpp:22
void InitializeSym(const Box< dim, T > &box, const Box< dim, T > &dom, const Ghost< dim, T > &g, T r_cut, openfpm::vector< Point< dim, T >> &pos, size_t g_m)
Initialize the symmetric Verlet-list.
Iterator for the neighborhood of the cell structures.
void initCl(CellListImpl &cli, openfpm::vector< Point< dim, T >> &pos, size_t g_m, size_t opt)
Fill the cell-list with data.
VerletList< dim, T, Mem_type, transform, CellListImpl > & operator=(const VerletList< dim, T, Mem_type, transform, CellListImpl > &vl)
Copy a verlet list.
CellListImpl cli
Interlal cell-list.
void clear()
Clear the cell list.
static void add(local_index p, openfpm::vector< local_index > &pc)
Add particle in the list of the domain particles.
This iterator iterate across the particles of a Cell-list following the Cell structure.
void Initialize(const Box< dim, T > &box, const Box< dim, T > &dom, T r_cut, openfpm::vector< Point< dim, T >> &pos, size_t g_m, size_t opt=VL_NON_SYMMETRIC)
Definition: Ghost.hpp:39
static void add(local_index p, openfpm::vector< local_index > &pc)
Add particle in the list of the domain particles.
VerletNNIterator< dim, VerletList< dim, T, Mem_type, transform, CellListImpl > > getNNIterator(size_t part_id)
Get the Neighborhood iterator.
Get the neighborhood iterator based on type.
void updateCrs(const Box< dim, T > &dom, T r_cut, openfpm::vector< Point< dim, T >> &pos, size_t &g_m, const openfpm::vector< size_t > &dom_c, const openfpm::vector< subsub_lin< dim >> &anom_c)
update the Verlet list
CellListImpl CellListImpl_
CellList implementation used for Verlet list construction.
static auto get(const PartIt &it, const openfpm::vector< Point< dim, T >> &v, Point< dim, T > &xp, size_t p, CellListImpl &cl, T r_cut) -> decltype(cl.template getNNIterator< NO_CHECK >(0))
Get the neighborhood.
Mem_type Mem_type_type
type for the local index
This class implement an NxN (dense) matrix.
Definition: Matrix.hpp:32
size_t getNNPart(size_t part_id) const
Return the number of neighborhood particles for the particle id.
void update(const Box< dim, T > &dom, T r_cut, openfpm::vector< Point< dim, T >> &pos, size_t &g_m, size_t opt)
update the Verlet list
VerletList()
Default Constructor.
const T & get(size_t i) const
Get coordinate.
Definition: Point.hpp:142
In general different NN scheme like full symmetric or CRS require different iterators over particles ...
VerletList< dim, T, Mem_type, transform, CellListImpl > & operator=(VerletList< dim, T, Mem_type, transform, CellListImpl > &&vl)
Copy the verlet list.
void InitializeCrs(const Box< dim, T > &box, const Box< dim, T > &dom, const Ghost< dim, T > &g, T r_cut, openfpm::vector< Point< dim, T >> &pos, size_t g_m)
Initialize the symmetric Verlet-list CRS scheme.
Mem_type::loc_index slot
Number of slot for each particle. Or maximum number of particles for each particle.
This class represent an N-dimensional box.
Definition: Box.hpp:56
VerletList(Box< dim, T > &box, T r_cut, openfpm::vector< Point< dim, T >> &pos, size_t g_m, size_t slot=VERLET_STARTING_NSLOT)
Verlet-list constructor.
static void add(local_index p, openfpm::vector< local_index > &pc)
Add particle in the list of the domain particles.
openfpm::vector< typename Mem_type::loc_index > & getParticleSeq()
Return the domain particle sequence.
T distance2(const Point< dim, T > &q)
It calculate the square distance between 2 points.
Definition: Point.hpp:240
size_t get_ndec()
Set the n_dec number.
void set_ndec(size_t n_dec)
Set the n_dec number.
VerletList(SpaceBox< dim, T > &box, Box< dim, T > &dom, T r_cut, openfpm::vector< Point< dim, T >> &pos, size_t g_m, size_t slot=VERLET_STARTING_NSLOT)
Cell list constructor.
void create(const openfpm::vector< Point< dim, T >> &pos, const openfpm::vector< Point< dim, T >> &pos2, const openfpm::vector< size_t > &dom, const openfpm::vector< subsub_lin< dim >> &anom, T r_cut, size_t g_m, CellListImpl &cl, size_t opt)
Create the Verlet list from a given cell-list.
VerletList(VerletList< dim, T, Mem_type, transform, CellListImpl > &&cell)
Copy constructor.
void swap(VerletList< dim, T, Mem_type, transform, CellListImpl > &vl)
Swap the memory.
~VerletList()
Destructor.
const Mem_type::loc_index & getStop(typename Mem_type::loc_index part_id)
Return the end point of the neighborhood for the particle p.
void create_(const openfpm::vector< Point< dim, T >> &pos, const openfpm::vector< Point< dim, T >> &pos2, const openfpm::vector< size_t > &dom, const openfpm::vector< subsub_lin< dim >> &anom, T r_cut, size_t g_m, CellListImpl &cli, size_t opt)
Create the Verlet list from a given cell-list.
Implementation of 1-D std::vector like structure.
Definition: map_vector.hpp:61
Class for FAST cell list implementation.
Definition: CellList.hpp:269
void addPart(size_t part_id, size_t ele)
Add a neighborhood particle to a particle.
void Initialize(CellListImpl &cli, T r_cut, const openfpm::vector< Point< dim, T >> &pos, const openfpm::vector< Point< dim, T >> &pos2, size_t g_m, size_t opt=VL_NON_SYMMETRIC)
Linearized version of subsub.
size_t size()
Return for how many particles has been constructed this verlet list.
const Mem_type::loc_index & get_lin(const typename Mem_type::loc_index *part_id)
Return the neighborhood id.
CellListImpl & getInternalCellList()
Get the internal cell-list used to construct the Verlet-list.