54 std::ostringstream error_message;
55 error_message <<
"The solid mesh pointer must be set.\n"
56 <<
"Use method set_solid_mesh(...)";
58 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
89 double block_setup_time = t_block_finish - t_block_start;
92 oomph_info <<
"Time for block_setup(...) [sec]: " << block_setup_time
101 if (F_block_preconditioner_pt == 0)
113 double get_B_time = t_get_B_finish - t_get_B_start;
114 oomph_info <<
"Time to get B [sec]: " << get_B_time <<
"\n";
139 double ivmm_assembly_time =
140 ivmm_assembly_finish_t - ivmm_assembly_start_t;
141 oomph_info <<
"Time to assemble inverse mass matrix [sec]: "
142 << ivmm_assembly_time <<
"\n";
148 b_pt->
multiply(*ivmm_pt, *temp_matrix_pt);
151 b_pt = temp_matrix_pt;
155 double t_BQ_time = t_BQ_finish - t_BQ_start;
156 oomph_info <<
"Time to generate BQ [sec]: " << t_BQ_time << std::endl;
166 double t_get_Bt_time = t_get_Bt_finish - t_get_Bt_start;
167 oomph_info <<
"Time to get Bt [sec]: " << t_get_Bt_time << std::endl;
173 b_pt->
multiply(*bt_pt, *p_matrix_pt);
177 double t_P_time = t_P_finish - t_P_start;
178 oomph_info <<
"Time to generate P matrix [sec]: " << t_P_time
188 ivmm_pt->
multiply(*bt_pt, *temp_matrix_pt);
191 bt_pt = temp_matrix_pt;
197 double t_QBt_time = t_QBt_finish - t_QBt_start;
198 oomph_info <<
"Time to generate QBt [sec]: " << t_QBt_time
212 double t_get_F_time = t_get_F_finish - t_get_F_start;
213 oomph_info <<
"Time to get F [sec]: " << t_get_F_time << std::endl;
219 f_pt->
multiply(*bt_pt, *aux_matrix_pt);
223 double t_aux_time = t_aux_matrix_finish - t_aux_matrix_start;
224 oomph_info <<
"Time to generate FQBt [sec]: " << t_aux_time
241 b_pt->
multiply(*aux_matrix_pt, *e_matrix_pt);
242 delete aux_matrix_pt;
247 double t_E_time = t_E_matrix_finish - t_E_matrix_start;
248 oomph_info <<
"Time to generate E (B*(F*Bt)) [sec]: " << t_E_time
259 double t_E_time = t_E_matvec_finish - t_E_matvec_start;
260 oomph_info <<
"Time to build E (BFBt) matrix vector operator E [sec]: "
261 << t_E_time << std::endl;
271 double t_get_Bt_time = t_get_Bt_finish - t_get_Bt_start;
272 oomph_info <<
"Time to get Bt [sec]: " << t_get_Bt_time << std::endl;
292 double ivmm_assembly_time =
293 ivmm_assembly_finish_t - ivmm_assembly_start_t;
294 oomph_info <<
"Time to assemble Q (inverse diagonal "
295 <<
"mass matrix) [sec]: " << ivmm_assembly_time <<
"\n";
305 double t_get_Bt_time = t_get_Bt_finish - t_get_Bt_start;
306 oomph_info <<
"Time to get Bt [sec]: " << t_get_Bt_time << std::endl;
321 double t_QBt_time = t_QBt_matrix_finish - t_QBt_matrix_start;
322 oomph_info <<
"Time to generate QBt [sec]: " << t_QBt_time
330 b_pt->
multiply(*bt_pt, *p_matrix_pt);
334 double t_p_time = t_p_matrix_finish - t_p_matrix_start;
335 oomph_info <<
"Time to generate P [sec]: " << t_p_time << std::endl;
348 double t_p_time = t_QBt_MV_finish - t_QBt_MV_start;
349 oomph_info <<
"Time to build QBt matrix vector operator [sec]: "
350 << t_p_time << std::endl;
361 double t_get_F_time = t_get_F_finish - t_get_F_start;
362 oomph_info <<
"Time to get F [sec]: " << t_get_F_time << std::endl;
373 double t_F_MV_time = t_F_MV_finish - t_F_MV_start;
374 oomph_info <<
"Time to build F Matrix Vector Operator [sec]: "
375 << t_F_MV_time << std::endl;
392 double t_get_Bt_time = t_get_Bt_finish - t_get_Bt_start;
393 oomph_info <<
"Time to get Bt [sec]: " << t_get_Bt_time << std::endl;
409 double t_Bt_MV_time = t_Bt_MV_finish - t_Bt_MV_start;
410 oomph_info <<
"Time to build Bt Matrix Vector Operator [sec]: "
411 << t_Bt_MV_time << std::endl;
438 double t_p_prec_time = t_p_prec_finish - t_p_prec_start;
439 oomph_info <<
"P sub-preconditioner setup time [sec]: " << t_p_prec_time
478 double t_f_prec_time = t_f_prec_finish - t_f_prec_start;
479 oomph_info <<
"F sub-preconditioner setup time [sec]: " << t_f_prec_time
499 std::ostringstream error_message;
500 error_message <<
"setup must be called before using preconditioner_solve";
502 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
508 std::ostringstream error_message;
509 error_message <<
"The vectors z and r must have the same number of "
512 OOMPH_CURRENT_FUNCTION,
513 OOMPH_EXCEPTION_LOCATION);
544 oomph_info <<
"LSC prec solve: Time for get block vector: "
545 << t_end - t_start << std::endl;
556 std::ostringstream error_message;
557 error_message <<
"P_preconditioner_pt has not been set.";
559 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
570 oomph_info <<
"LSC prec solve: First P solve [nrow="
588 another_temp_vec.
clear();
598 oomph_info <<
"LSC prec solve: E matrix vector product: "
599 << t_end - t_start << std::endl;
606 another_temp_vec.
clear();
613 oomph_info <<
"LSC prec solve: Second P solve [nrow="
627 temp_vec -= another_temp_vec;
644 oomph_info <<
"LSC prec solve: G matrix vector product: "
645 << t_end - t_start << std::endl;
653 another_temp_vec.
clear();
658 another_temp_vec += temp_vec;
667 std::ostringstream error_message;
668 error_message <<
"F_preconditioner_pt has not been set.";
670 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
690 oomph_info <<
"LSC prec solve: F solve [nrow="
693 oomph_info <<
"LSC prec solve: Overall " << t_end - t_start_overall
733 unsigned nproc = this->
comm_pt()->nproc();
736 unsigned my_rank = this->
comm_pt()->my_rank();
742 unsigned first_lookup_row = 0;
743 unsigned last_lookup_row = 0;
775 for (
unsigned e = 0;
e < n_el;
e++)
797 std::ostringstream error_message;
798 error_message <<
"Failed cast to "
799 <<
"SolidElementWithDiagonalMassMatrix*\n"
800 <<
"Element is of type: "
806 "PressureBasedSolidLSCPreconditioner::assemble_"
807 "mass_matrix_diagonal()",
808 OOMPH_EXCEPTION_LOCATION);
817 for (
unsigned i = 0;
i < el_dof;
i++)
823 if (eqn_number >= first_lookup_row && eqn_number <= last_lookup_row)
832 for (
unsigned p = 0; p < nproc; p++)
834 if (index >= displ_dist_pt->
first_row(p) &&
842 m_values[index -
first_row] += el_vmm_diagonal[
i];
847 classified_contributions_send[p].push_back(
849 classified_indices_send[p].push_back(index);
874 unclassified_contributions_send[p].push_back(el_vmm_diagonal[
i]);
875 unclassified_indices_send[p].push_back(eqn_number);
886 unsigned* n_unclassified_send =
new unsigned[nproc];
887 for (
unsigned p = 0; p < nproc; p++)
891 n_unclassified_send[p] = 0;
895 n_unclassified_send[p] = unclassified_contributions_send[p].size();
900 unsigned* n_unclassified_recv =
new unsigned[nproc];
901 MPI_Alltoall(n_unclassified_send,
910 MPI_Aint base_displacement;
911 MPI_Get_address(m_values, &base_displacement);
920 for (
unsigned p = 0; p < nproc; p++)
925 if (n_unclassified_recv[p] > 0)
927 unclassified_contributions_recv[p] =
928 new double[n_unclassified_recv[p]];
929 unclassified_indices_recv[p] =
new unsigned[n_unclassified_recv[p]];
932 MPI_Datatype recv_types[2];
933 MPI_Aint recv_displacements[2];
938 n_unclassified_recv[p], MPI_DOUBLE, &recv_types[0]);
939 MPI_Type_commit(&recv_types[0]);
940 MPI_Get_address(unclassified_contributions_recv[p],
941 &recv_displacements[0]);
942 recv_displacements[0] -= base_displacement;
947 n_unclassified_recv[p], MPI_UNSIGNED, &recv_types[1]);
948 MPI_Type_commit(&recv_types[1]);
949 MPI_Get_address(unclassified_indices_recv[p],
950 &recv_displacements[1]);
951 recv_displacements[1] -= base_displacement;
955 MPI_Datatype final_recv_type;
956 MPI_Type_create_struct(
957 2, recv_sz, recv_displacements, recv_types, &final_recv_type);
958 MPI_Type_commit(&final_recv_type);
963 m_values, 1, final_recv_type, p, 0,
comm_pt()->mpi_comm(), &req);
964 unclassified_recv_requests.push_back(req);
965 unclassified_recv_proc.push_back(p);
966 MPI_Type_free(&recv_types[0]);
967 MPI_Type_free(&recv_types[1]);
968 MPI_Type_free(&final_recv_type);
972 if (n_unclassified_send[p] > 0)
975 MPI_Datatype send_types[2];
976 MPI_Aint send_displacements[2];
981 n_unclassified_send[p], MPI_DOUBLE, &send_types[0]);
982 MPI_Type_commit(&send_types[0]);
983 MPI_Get_address(&unclassified_contributions_send[p][0],
984 &send_displacements[0]);
985 send_displacements[0] -= base_displacement;
990 n_unclassified_send[p], MPI_UNSIGNED, &send_types[1]);
991 MPI_Type_commit(&send_types[1]);
992 MPI_Get_address(&unclassified_indices_send[p][0],
993 &send_displacements[1]);
994 send_displacements[1] -= base_displacement;
998 MPI_Datatype final_send_type;
999 MPI_Type_create_struct(
1000 2, send_sz, send_displacements, send_types, &final_send_type);
1001 MPI_Type_commit(&final_send_type);
1006 m_values, 1, final_send_type, p, 0,
comm_pt()->mpi_comm(), &req);
1007 unclassified_send_requests.push_back(req);
1008 MPI_Type_free(&send_types[0]);
1009 MPI_Type_free(&send_types[1]);
1010 MPI_Type_free(&final_send_type);
1016 unsigned n_unclassified_recv_req = unclassified_recv_requests.size();
1017 while (n_unclassified_recv_req > 0)
1022 MPI_Waitany(n_unclassified_recv_req,
1023 &unclassified_recv_requests[0],
1026 unsigned p = unclassified_recv_proc[req_num];
1027 unclassified_recv_requests.erase(unclassified_recv_requests.begin() +
1029 unclassified_recv_proc.erase(unclassified_recv_proc.begin() + req_num);
1030 n_unclassified_recv_req--;
1034 unsigned n_recv = n_unclassified_recv[p];
1035 for (
unsigned i = 0;
i < n_recv;
i++)
1037 unsigned eqn_number = unclassified_indices_recv[p][
i];
1045 for (
unsigned pp = 0; pp < nproc; pp++)
1047 if (index >= displ_dist_pt->
first_row(pp) &&
1048 (index < (displ_dist_pt->
first_row(pp) +
1056 unclassified_contributions_recv[p][
i];
1061 double v = unclassified_contributions_recv[p][
i];
1062 classified_contributions_send[pp].push_back(v);
1063 classified_indices_send[pp].push_back(index);
1071 delete[] unclassified_contributions_recv[p];
1072 delete[] unclassified_indices_recv[p];
1074 delete[] n_unclassified_recv;
1083 unsigned* n_classified_send =
new unsigned[nproc];
1084 for (
unsigned p = 0; p < nproc; p++)
1088 n_classified_send[p] = 0;
1092 n_classified_send[p] = classified_contributions_send[p].size();
1097 unsigned* n_classified_recv =
new unsigned[nproc];
1098 MPI_Alltoall(n_classified_send,
1113 for (
unsigned p = 0; p < nproc; p++)
1118 if (n_classified_recv[p] > 0)
1120 classified_contributions_recv[p] =
new double[n_classified_recv[p]];
1121 classified_indices_recv[p] =
new unsigned[n_classified_recv[p]];
1124 MPI_Datatype recv_types[2];
1125 MPI_Aint recv_displacements[2];
1129 MPI_Type_contiguous(
1130 n_classified_recv[p], MPI_DOUBLE, &recv_types[0]);
1131 MPI_Type_commit(&recv_types[0]);
1132 MPI_Get_address(classified_contributions_recv[p],
1133 &recv_displacements[0]);
1134 recv_displacements[0] -= base_displacement;
1138 MPI_Type_contiguous(
1139 n_classified_recv[p], MPI_UNSIGNED, &recv_types[1]);
1140 MPI_Type_commit(&recv_types[1]);
1141 MPI_Get_address(classified_indices_recv[p], &recv_displacements[1]);
1142 recv_displacements[1] -= base_displacement;
1146 MPI_Datatype final_recv_type;
1147 MPI_Type_create_struct(
1148 2, recv_sz, recv_displacements, recv_types, &final_recv_type);
1149 MPI_Type_commit(&final_recv_type);
1154 m_values, 1, final_recv_type, p, 0,
comm_pt()->mpi_comm(), &req);
1155 classified_recv_requests.push_back(req);
1156 classified_recv_proc.push_back(p);
1157 MPI_Type_free(&recv_types[0]);
1158 MPI_Type_free(&recv_types[1]);
1159 MPI_Type_free(&final_recv_type);
1163 if (n_classified_send[p] > 0)
1166 MPI_Datatype send_types[2];
1167 MPI_Aint send_displacements[2];
1171 MPI_Type_contiguous(
1172 n_classified_send[p], MPI_DOUBLE, &send_types[0]);
1173 MPI_Type_commit(&send_types[0]);
1174 MPI_Get_address(&classified_contributions_send[p][0],
1175 &send_displacements[0]);
1176 send_displacements[0] -= base_displacement;
1180 MPI_Type_contiguous(
1181 n_classified_send[p], MPI_UNSIGNED, &send_types[1]);
1182 MPI_Type_commit(&send_types[1]);
1183 MPI_Get_address(&classified_indices_send[p][0],
1184 &send_displacements[1]);
1185 send_displacements[1] -= base_displacement;
1189 MPI_Datatype final_send_type;
1190 MPI_Type_create_struct(
1191 2, send_sz, send_displacements, send_types, &final_send_type);
1192 MPI_Type_commit(&final_send_type);
1197 m_values, 1, final_send_type, p, 0,
comm_pt()->mpi_comm(), &req);
1198 classified_send_requests.push_back(req);
1199 MPI_Type_free(&send_types[0]);
1200 MPI_Type_free(&send_types[1]);
1201 MPI_Type_free(&final_send_type);
1207 unsigned n_classified_recv_req = classified_recv_requests.size();
1208 while (n_classified_recv_req > 0)
1213 MPI_Waitany(n_classified_recv_req,
1214 &classified_recv_requests[0],
1217 unsigned p = classified_recv_proc[req_num];
1218 classified_recv_requests.erase(classified_recv_requests.begin() +
1220 classified_recv_proc.erase(classified_recv_proc.begin() + req_num);
1221 n_classified_recv_req--;
1225 unsigned n_recv = n_classified_recv[p];
1226 for (
unsigned i = 0;
i < n_recv;
i++)
1228 m_values[classified_indices_recv[p][
i] -
first_row] +=
1229 classified_contributions_recv[p][
i];
1233 delete[] classified_contributions_recv[p];
1234 delete[] classified_indices_recv[p];
1238 unsigned n_unclassified_send_req = unclassified_send_requests.size();
1239 if (n_unclassified_send_req > 0)
1241 MPI_Waitall(n_unclassified_send_req,
1242 &unclassified_send_requests[0],
1245 delete[] unclassified_contributions_send;
1246 delete[] unclassified_indices_send;
1247 delete[] n_unclassified_send;
1250 unsigned n_classified_send_req = classified_send_requests.size();
1251 if (n_classified_send_req > 0)
1253 MPI_Waitall(n_classified_send_req,
1254 &classified_send_requests[0],
1257 delete[] classified_indices_send;
1258 delete[] classified_contributions_send;
1259 delete[] n_classified_recv;
1260 delete[] n_classified_send;
1271 for (
unsigned e = 0;
e < n_el;
e++)
1286 if (cast_el_pt == 0)
1292 std::ostringstream error_message;
1293 error_message <<
"Failed cast to "
1294 <<
"SolidElementWithDiagonalMassMatrix*\n"
1295 <<
"Element is of type: "
1301 "PressureBasedSolidLSCPreconditioner::assemble_mass_"
1302 "matrix_diagonal()",
1303 OOMPH_EXCEPTION_LOCATION);
1313 for (
unsigned i = 0;
i < el_dof;
i++)
1327 m_values[index -
first_row] += el_vmm_diagonal[
i];
1339 m_values[
i] = 1 / m_values[
i];
const LinearAlgebraDistribution * master_distribution_pt() const
Access function to the distribution of the master preconditioner. If this preconditioner does not hav...
void return_block_vector(const unsigned &n, const DoubleVector &b, DoubleVector &v) const
Takes the n-th block ordered vector, b, and copies its entries to the appropriate entries in the natu...
unsigned ndof_types_in_mesh(const unsigned &i) const
Return the number of DOF types in mesh i. WARNING: This should only be used by the upper-most master ...
bool any_mesh_distributed() const
Check if any of the meshes are distributed. This is equivalent to problem.distributed() and is used a...
void get_block(const unsigned &i, const unsigned &j, CRDoubleMatrix &output_matrix, const bool &ignore_replacement_block=false) const
Put block (i,j) into output_matrix. This block accounts for any coarsening of dof types and any repla...
int index_in_block(const unsigned &i_dof) const
Given a global dof number, returns the index in the block it belongs to. This is the overall index,...
const LinearAlgebraDistribution * block_distribution_pt(const unsigned &b) const
Access function to the block distributions (const version).
void get_block_vector(const unsigned &n, const DoubleVector &v, DoubleVector &b) const
Takes the naturally ordered vector, v and returns the n-th block vector, b. Here n is the block numbe...
int block_number(const unsigned &i_dof) const
Return the block number corresponding to a global index i_dof.
CRDoubleMatrix * matrix_pt() const
Access function to matrix_pt. If this is the master then cast the matrix pointer to MATRIX*,...
bool is_subsidiary_block_preconditioner() const
Return true if this preconditioner is a subsidiary preconditioner.
unsigned ndof_types() const
Return the total number of DOF types.
void turn_into_subsidiary_block_preconditioner(BlockPreconditioner< MATRIX > *master_block_prec_pt, const Vector< unsigned > &doftype_in_master_preconditioner_coarse)
Function to turn this preconditioner into a subsidiary preconditioner that operates within a bigger "...
void setup_matrix_vector_product(MatrixVectorProduct *matvec_prod_pt, CRDoubleMatrix *block_pt, const Vector< unsigned > &block_col_indices)
Setup a matrix vector product. matvec_prod_pt is a pointer to the MatrixVectorProduct,...
virtual void block_setup()
Determine the size of the matrix blocks and setup the lookup schemes relating the global degrees of f...
void set_mesh(const unsigned &i, const Mesh *const mesh_pt, const bool &allow_multiple_element_type_in_mesh=false)
Set the i-th mesh for this block preconditioner. Note: The method set_nmesh(...) must be called befor...
A class for compressed row matrices. This is a distributable object.
void multiply(const DoubleVector &x, DoubleVector &soln) const
Multiply the matrix by the vector x: soln=Ax.
void build_without_copy(const unsigned &ncol, const unsigned &nnz, double *value, int *column_index, int *row_start)
keeps the existing distribution and just matrix that is stored without copying the matrix data
bool distributed() const
distribution is serial or distributed
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
unsigned nrow() const
access function to the number of global rows.
unsigned nrow_local() const
access function for the num of local rows on this processor.
unsigned first_row() const
access function for the first row on this processor
A vector in the mathematical sense, initially developed for linear algebra type applications....
void build(const DoubleVector &old_vector)
Just copys the argument DoubleVector.
void clear()
wipes the DoubleVector
bool is_halo() const
Is this element a halo?
unsigned ndof() const
Return the number of equations/dofs in the element.
unsigned long eqn_number(const unsigned &ieqn_local) const
Return the global equation number corresponding to the ieqn_local-th local equation number.
Describes the distribution of a distributable linear algebra type object. Typically this is a contain...
unsigned first_row() const
access function for the first row on this processor. If not distributed then this is just zero.
unsigned nrow() const
access function to the number of global rows.
unsigned nrow_local() const
access function for the num of local rows on this processor. If no MPI then Nrow is returned.
Matrix vector product helper class - primarily a wrapper to Trilinos's Epetra matrix vector product m...
void multiply_transpose(const DoubleVector &x, DoubleVector &y) const
Apply the transpose of the operator to the vector x and return the result in the vector y.
void multiply(const DoubleVector &x, DoubleVector &y) const
Apply the operator to the vector x and return the result in the vector y.
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
unsigned long nelement() const
Return number of elements in the mesh.
An OomphLibError object which should be thrown when an run-time error is encountered....
An OomphLibWarning object which should be created as a temporary object to issue a warning....
void setup(DoubleMatrixBase *matrix_pt)
Setup the preconditioner: store the matrix pointer and the communicator pointer then call preconditio...
virtual void preconditioner_solve(const DoubleVector &r, DoubleVector &z)=0
Apply the preconditioner. Pure virtual generic interface function. This method should apply the preco...
virtual const OomphCommunicator * comm_pt() const
Get function for comm pointer.
MatrixVectorProduct * QBt_mat_vec_pt
MatrixVectorProduct operator for QBt if BFBt is not to be formed.
bool Form_BFBt_product
indicates whether BFBt should be formed or the component matrices should be retained....
CRDoubleMatrix * assemble_mass_matrix_diagonal()
Helper function to assemble the diagonal of the mass matrix from the elemental contributions defined ...
bool Preconditioner_has_been_setup
Control flag is true if the preconditioner has been setup (used so we can wipe the data when the prec...
Preconditioner * F_preconditioner_pt
Pointer to the 'preconditioner' for the F matrix.
MatrixVectorProduct * E_mat_vec_pt
MatrixVectorProduct operator for E (BFBt) if BFBt is to be formed.
bool Doc_time
Set Doc_time to true for outputting results of timings.
Mesh * Solid_mesh_pt
the pointer to the mesh of block preconditionable solid elements.
bool F_preconditioner_is_block_preconditioner
Boolean indicating whether the momentum system preconditioner is a block preconditioner.
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to Vector r.
void setup()
Broken assignment operator.
MatrixVectorProduct * Bt_mat_vec_pt
MatrixVectorProduct operator for Bt;.
bool Using_default_p_preconditioner
flag indicating whether the default P preconditioner is used
MatrixVectorProduct * F_mat_vec_pt
MatrixVectorProduct operator for F if BFBt is not to be formed.
void clean_up_memory()
Helper function to delete preconditioner data.
bool Using_default_f_preconditioner
flag indicating whether the default F preconditioner is used
Preconditioner * P_preconditioner_pt
Pointer to the 'preconditioner' for the pressure matrix.
bool P_matrix_using_scaling
Control flag is true if mass matrix diagonal scaling is used in the Schur complement approximation.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
virtual void get_mass_matrix_diagonal(Vector< double > &mass_diag)=0
Get the diagonal of whatever represents the mass matrix in the specific preconditionable element....
An interface to allow SuperLU to be used as an (exact) Preconditioner.
double timer()
returns the time in seconds after some point in past
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...