16#include <Convection_Diffusion_Concentration.h>
17#include <Champ_front_contact_fictif_VEF.h>
18#include <Modele_turbulence_scal_base.h>
19#include <Op_Diff_VEF_Anisotrope_Face.h>
20#include <Modele_turbulence_hyd_base.h>
21#include <Raccord_distant_homogene.h>
22#include <Champ_front_contact_VEF.h>
23#include <Champ_Fonc_P0_VEF.h>
24#include <Format_Post_Med.h>
25#include <Domaine_Cl_VEF.h>
26#include <Champ_Uniforme.h>
27#include <distances_VEF.h>
28#include <Probleme_base.h>
29#include <Pb_Conduction.h>
30#include <Schema_Comm.h>
31#include <Constituant.h>
32#include <Interprete.h>
53 nom_inco =
"temperature";
56 Cerr <<
"Champ_front_contact_VEF::readOn : " <<
nom_pb1 <<
" " <<
nom_bord1 <<
" " << nom_inco << finl;
57 Cerr <<
" connecte a : " <<
nom_pb2 <<
" " <<
nom_bord2 <<
" " << nom_inco << finl;
89 if (!sub_type(Raccord_distant_homogene, frontiere_opposee))
92 Cerr <<
"Error, the boundary " << frontiere_opposee.
le_nom() <<
" should be a Raccord." << finl;
93 Cerr <<
"Add in your data file between the definition and the partition of the domain " << nom_domaine_oppose <<
" :" << finl;
94 Cerr <<
"Modif_bord_to_raccord " << nom_domaine_oppose <<
" " << frontiere_opposee.
le_nom() << finl;
97 Raccord_distant_homogene& raccord_distant = ref_cast_non_const(Raccord_distant_homogene, frontiere_opposee);
98 raccord_distant.
initialise(frontiere_locale, domaine_dis_locale, domaine_dis_opposee);
143 Nom nom_inco1, nom_inco2;
144 nom_inco1 = nom_inco;
145 nom_inco2 = nom_inco;
152 nom_inco1 =
"concentration";
162 nom_inco2 =
"concentration";
167 if (nom_inco1 != nom_inco2)
169 Cerr <<
"A contact boundary condition is incorrectly specified" << finl;
170 Cerr <<
"There is an inconsistency in the unknown involved on both sides of the contact boundary" << finl;
204 const DoubleTab& inco_valeurs = l_inconnue->
valeurs(temps);
209 const DoubleVect& vol = le_dom_dis.
volumes();
211 const IntTab& elem_faces = le_dom_dis.
elem_faces();
216 const int nb_faces = la_front_vf.
nb_faces();
219 DoubleTab coeff_lam, coeff_turb;
225 coeff_lam = ref_cast(
Constituant,le_milieu).diffusivite_constituant().valeurs();
228 int ind_loi_paroi = 0;
244 for (
int n_bord = 0; n_bord < le_dom_dis.
domaine().nb_front_Cl(); n_bord++)
248 for (
int ind_face = 0; ind_face < nb_faces; ind_face++)
254 double surface_pond, surface_face;
256 const int nd = coeff_lam.
nb_dim();
257 const bool is_uniforme = coeff_lam.
dimension(0) == 1;
259 for (
int fac_front = 0; fac_front < nb_faces; fac_front++)
265 const int fac_glob = fac_front + ndeb;
266 int num = face_voisins(fac_glob, 0);
268 num = face_voisins(fac_glob, 1);
273 ratio += (face_normales(fac_glob, i) * face_normales(fac_glob, i));
282 e_idx = is_uniforme ? 0 : num;
285 k_eff = coeff_lam(e_idx);
291 n[i] = face_normales(fac_glob, i) / ratio;
295 k_eff = coeff_lam(e_idx, 0);
299 k_eff += n[i] * n[i] * coeff_lam(e_idx, i);
307 const double Kij = 0.5 * (coeff_lam(e_idx, i *
dimension + j) + coeff_lam(e_idx, j *
dimension + i));
308 k_eff += n[i] * n[j] * Kij;
312 k_eff = coeff_lam(e_idx, 0);
318 n[i] = face_normales(fac_glob, i) / ratio;
322 k_eff += n[i] * coeff_lam(e_idx, i, j) * n[j];
329 k_eff += coeff_turb(num);
333 for (
int i = 0; i < nb_faces_elem; i++)
337 const int j = elem_faces(num, i);
342 surface_pond -= (face_normales(j, kk) * le_dom_dis.
oriente_normale(j, num) * face_normales(fac_glob, kk) * le_dom_dis.
oriente_normale(fac_glob, num)) / (surface_face * surface_face);
343 Scal_moy(fac_front) += inco_valeurs(j) * surface_pond;
348 for (
int fac = 0; fac <
dimension + 1; fac++)
351 const int fac_loc = elem_faces(num, fac);
353 if (fac_loc != fac_glob)
354 gradient_num_local(fac_front) += (signe * face_normales(fac_glob, i) / ratio * face_normales(fac_loc, i) * inco_valeurs(fac_loc));
356 gradient_fro_local(fac_front) += (signe * face_normales(fac_loc, i) / ratio * face_normales(fac_loc, i));
363 if (ind_loi_paroi == 1)
369 const double coeff_equiv = k_eff / d_equiv(fac_front);
384 const Frontiere& la_front=la_frontiere_dis->frontiere();
389 DoubleVect gradient_num_transf_autre_pb(nb_faces);
390 DoubleVect gradient_fro_transf_autre_pb(nb_faces);
393 Cerr <<
"Warning: You are using a contact condition Champ_front_contact_VEF on boundary " <<
nom_bord1 <<
" of problem "<<
nom_pb1 <<
" " << finl;
394 Cerr <<
"You must have an equivalent Champ_front_contact_VEF on boundary " <<
nom_bord2 <<
" of problem "<<
nom_pb2<<
" " << finl;
397 trace_face_raccord(fr_vf_autre_pb.valeur(),ch_fr_autre_pb->gradient_num_transf,gradient_num_transf_autre_pb);
398 trace_face_raccord(fr_vf_autre_pb.valeur(),ch_fr_autre_pb->gradient_fro_transf,gradient_fro_transf_autre_pb);
404 for (
int fac_front=0; fac_front<nb_faces; fac_front++)
406 tab(fac_front,0)= -(
gradient_num_local(fac_front) + gradient_num_transf_autre_pb(fac_front))
419 const Frontiere& la_front=la_frontiere_dis->frontiere();
422 DoubleVect Scal_moy_autre_pb(nb_faces);
423 trace_face_raccord(fr_vf_autre_pb.valeur(),ch_fr_autre_pb->Scal_moy,Scal_moy_autre_pb);
428 for (
int fac_front=0; fac_front<nb_faces; fac_front++)
430 if (
Scal_moy(fac_front) > Scal_moy_autre_pb(fac_front))
432 if ((tab(fac_front,0)>
Scal_moy(fac_front)) || (tab(fac_front,0)<Scal_moy_autre_pb(fac_front)))
434 if (tab(fac_front,0)>
Scal_moy(fac_front))
436 Cerr<<
"Warning, Tp is not between the temperatures"<<finl;
437 Cerr<<
"of the fluid and solid near the wall"<<finl;
438 Cerr<<
"Tp("<<fac_front<<
") = "<<tab(fac_front,0)<<
" is too high"<<finl;
439 Cerr<<
"by DT = "<<tab(fac_front,0)-
Scal_moy(fac_front)<<
" K"<<finl;
443 Cerr<<
"Warning, Tp is not between the temperatures"<<finl;
444 Cerr<<
"of the fluid and solid near the wall"<<finl;
445 Cerr<<
"Tp("<<fac_front<<
") = "<<tab(fac_front,0)<<
" is too low"<<finl;
446 Cerr<<
"by DT = "<<Scal_moy_autre_pb(fac_front)-tab(fac_front,0)<<
" K"<<finl;
452 if ((tab(fac_front,0)<
Scal_moy(fac_front)) || (tab(fac_front,0)>Scal_moy_autre_pb(fac_front)))
454 if (tab(fac_front,0)<
Scal_moy(fac_front))
456 Cerr<<
"Warning, Tp is not between the temperatures"<<finl;
457 Cerr<<
"of the fluid and solid near the wall"<<finl;
458 Cerr<<
"Tp("<<fac_front<<
") = "<<tab(fac_front,0)<<
" is too low"<<finl;
459 Cerr<<
"by DT = "<<
Scal_moy(fac_front)-tab(fac_front,0)<<
" K"<<finl;
463 Cerr<<
"Warning, Tp is not between the temperatures"<<finl;
464 Cerr<<
"of the fluid and solid near the wall"<<finl;
465 Cerr<<
"Tp("<<fac_front<<
") = "<<tab(fac_front,0)<<
" is too high"<<finl;
466 Cerr<<
"by DT = "<<tab(fac_front,0)-Scal_moy_autre_pb(fac_front)<<
" K"<<finl;
484 return l_inconnue.valeur();
498 Cerr <<
"\nError in Champ_front_contact_VEF::equation() : not able to return the equation !" << finl;
534 const DoubleVect& vol = le_dom_dis.
volumes();
539 int nb_faces = la_front_vf.
nb_faces();
543 for (fac_front = 0; fac_front<nb_faces; fac_front++)
545 int fac = fac_front + ndeb;
546 int num = face_voisins(fac,0);
547 if (num < 0) num = face_voisins(fac,1);
551 for (
int i=0; i<
dimension; i++) ratio += (face_normales(fac,i) * face_normales(fac,i));
560 alpha=tab_alpha(num);
563 double volume = vol(num);
578 for (num_cl = 0; num_cl<zcl.
nb_cond_lim(); num_cl++)
588 if (ch_fr_autre_pb->nom_pb1 ==
nom_pb1)
591 Cerr<<
"Warning, error when reading Champ_Front_Contact_VEF"<<finl;
592 Cerr<<
"The syntax to use is: local_pb_name local_boundary_name remote_pb_name remote_boundary_name"<<finl;
604 if (sub_type(Raccord_distant_homogene,fr_vf.
frontiere()))
612 Cerr <<
"The boundary named " << fr_vf.
frontiere().
le_nom() <<
" is not a 'Raccord Distant Homogene'" << finl;
613 Cerr <<
"Use keyword modif_bord_to_raccord to change the boundary of kind Paroi into a boundary of kind Raccord" << finl;
614 Cerr <<
"after you read the meshes during the partitioning." << finl;
618 int nb_fac_front=x.
size();
619 for(
int fac_front=0; fac_front<nb_fac_front; fac_front++)
632 const Frontiere& la_front = la_frontiere_dis->frontiere();
646 const DoubleTab& xv1 = le_dom_dis1.
xv();
649 const IntTab& elem_faces = le_dom_dis1.
elem_faces();
664 const DoubleTab& xv2 = le_dom_dis2.
xv();
669 int i,j,k,temoin,temoin_tot;
674 if (std::fabs(xv1(ndeb1,ii) - xv1(ndeb1+nb_faces,ii)) > erreur )
675 erreur = std::fabs(xv1(ndeb1,ii) - xv1(ndeb1+nb_faces,ii));
696 int nb_faces1 = la_front_vf1.
nb_faces();
697 int nb_faces2 = la_front_vf2.
nb_faces();
699 if(nb_faces1!=nb_faces2)
701 Cerr <<
"Warning, the number of faces (" << nb_faces1 <<
") on the boundary " << la_front_vf1.
le_nom();
702 Cerr <<
" of the domain " << le_dom_dis1.
domaine().
le_nom() << finl;
703 Cerr <<
"is different of the number of faces (" << nb_faces2 <<
") on the boundary " << la_front_vf2.
le_nom();
704 Cerr <<
" of the domain " << le_dom_dis2.
domaine().
le_nom() <<
" ..." << finl;
705 Cerr <<
"The exchange condition with the paroi_contact can't succeed!" << finl;
706 Nom fichier=
"connectivity_failed_";
707 Nom fichier_med=
"connectivity_failed_";
709 if(nb_faces1>nb_faces2)
715 connectivity_failed(le_dom_dis1, nb_faces1, ndeb1, le_dom_dis2, nb_faces2, ndeb2, fichier, fichier_med);
723 connectivity_failed(le_dom_dis2, nb_faces2, ndeb2, le_dom_dis1, nb_faces1, ndeb1, fichier, fichier_med);
727 Cerr <<
"have not the same number of faces." << finl;
728 Cerr <<
"Coincidence between meshes may be recovered " << finl;
729 Cerr <<
"by cutting mesh associated to " << nom_pb << finl;
730 Cerr <<
"thanks to decouper_bord_coincident keyword or HOMARD tool (see reference manual)." << finl;
741 for (i=0; i<nb_faces; i++)
748 int elem_voisin=face_voisin(ndeb1+i,0);
750 elem_voisin=face_voisin(ndeb1+i,1);
753 for (
int f=0; f<nbf; f++)
755 int f2=elem_faces(elem_voisin,f);
757 d1=std::min(d1,distance_2D(f2,elem_voisin,le_dom_dis1));
759 d1=std::min(d1,distance_3D(f2,elem_voisin,le_dom_dis1));
763 for (j=i; j<nb_faces; j++)
768 if (std::fabs(xv1(ndeb1+i,k) - xv2(ndeb2+j,k)) > erreur)
break;
794 if (std::fabs(xv1(ndeb1+i,k) - xv2(ndeb2+j,k)) > erreur)
break;
820 Cerr<<
" no connectivity found for face : "<<ndeb1+i<<
" located at : x= "<<xv1(ndeb1+i,0)<<
" y= "<<xv1(ndeb1+i,1)<<finl;
822 Cerr<<
" no connectivity found for face : "<<ndeb1+i<<
" located at : x= "<<xv1(ndeb1+i,0)<<
" y= "<<xv1(ndeb1+i,1)<<
" z= "<<xv1(ndeb1+i,2)<<finl;
829 Cerr<<
" Process stopped at Champ_front_contact_VEF::remplir_connect_bords() "<<finl;
833 ArrOfInt inv_connect_bords;
834 inv_connect_bords.
resize_array(nb_faces, RESIZE_OPTIONS::NOCOPY_NOINIT);
835 inv_connect_bords=-1;
836 for (i=0; i<nb_faces; i++)
840 if (min_array(inv_connect_bords) < 0)
842 Cerr<<
"Problem creating connect_bord: the mapping is not a bijection"<<finl;
843 Cerr<<
"inverse array "<<inv_connect_bords<<finl;
853 int size_cl = conds_lim.size();
855 int elem_vois, elem_vois_autre_fr;
859 int elem_vois_face_1, elem_vois_face_2;
862 for (
int ind_face_1=0; ind_face_1<size; ind_face_1++)
865 for (
int ind_face_2 =0; ind_face_2<size; ind_face_2++)
867 if (ind_face_1!=ind_face_2)
870 if ((elem_vois_face_1==elem_vois_face_2) && (elem_vois_face_1!=-1))
880 for (
int num_cl=0; num_cl<size_cl; num_cl++)
891 int size_autre_fr = elems_autre_fr.
size();
892 for (
int ind_face =0; ind_face<size; ind_face++)
895 for (
int ind_face_autre_fr =0; ind_face_autre_fr<size_autre_fr; ind_face_autre_fr++)
897 elem_vois_autre_fr = elems_autre_fr[ind_face_autre_fr];
898 if ((elem_vois==elem_vois_autre_fr) && (elem_vois!=-1))
912 const IntTab& face_voisins1 = le_dom_dis1.
face_voisins();
913 int nb_faces = la_front_vf1.
nb_faces();
916 int voisin_0, voisin_1;
921 for (
int face=0; face<nb_faces; face++)
924 voisin_0 = face_voisins1(ndeb+face,0);
925 voisin_1 = face_voisins1(ndeb+face,1);
938 const DoubleTab& xv1 = le_dom_dis1.
xv();
941 int size_cl = conds_lim.size();
943 const Nom& nom_dom = l_inconnue1->equation().probleme().domaine().
le_nom();
945 for (
int num_cl=0; num_cl<size_cl; num_cl++)
957 for (
int i=0; i<faces_coin_fr.
size(); i++)
959 if (faces_coin_fr(i)!=0)
962 Cerr<<
"The following face of boundary "<<nom_bord_fr<<
" is a corner face for domain "<<nom_dom<<finl;
964 Cerr<<
"x_"<<k<<
" "<<xv1(ndeb_fr+i,k)<<finl;
971 Cerr<<
"The Champ_front_contact_VEF implementation is not available for this situation"<<finl;
972 Cerr<<
"Split the affected mesh cell(s) using the VerifierCoin interpreter"<<finl;
973 Cerr<<
"or using Trianguler_H in 2D or Tetraedriser_homogene in 3D"<<finl;
979 const Domaine_VEF& zvef2,
int& nb_faces2,
int& ndeb2,
980 Nom& fichier,
Nom& fichier_med)
984 const IntTab& elem_faces2 = zvef2.
elem_faces();
985 int nb_elem2 = zvef2.
nb_elem();
987 const DoubleTab& xv1 = zvef1.
xv();
990 int fac,elem,face1,face2,elem2,trouve;
999 chp.
nommer(
"Raccord_Homard");
1000 DoubleTab& chp_val = chp.
valeurs();
1005 for (fac=0; fac<nb_faces1; fac++)
1016 Cerr <<
"Problem searching for the associated element!" << finl;
1029 fic << nb_faces2 << finl;
1030 fic << nb_faces1 << finl;
1032 for (fac=0; fac<nb_faces2; fac++)
1035 elem2=face_voisin2(face2,0);
1036 if (elem2==-1) elem2=face_voisin2(face2,1);
1040 for(j=0; j<nbf; j++)
1041 if(face2==elem_faces2(elem2,j))
1049 Cerr <<
"Problem searching for the local index!" << finl;
1053 fic << chp_val(elem2) <<
" " << fac <<
" " << elem2 <<
" " << j << finl;
1065 for (elem=0; elem<nb_elem2; elem++)
1067 if(chp_val(elem)==(2*(
dimension-1))) chp_val(elem)=1;
1068 else chp_val(elem)=0;
1070 Nom bis(fichier_med);
1072 fichier_med.
prefix(
".med");
1073 const Domaine& dom2 = zvef2.
domaine();
1077 nom_compos[0]=chp.
le_nom();
class Ch_front_var_instationnaire_dep This abstract class represents a field on a boundary,
int initialiser(double temps, const Champ_Inc_base &inco) override
Initialization at the beginning of calculation.
void dimensionner(int, int)
Sets the number of components and the number of nodal values.
DoubleTab & valeurs() override
Overrides Champ_base::valeurs() Returns the array of values.
void associer_domaine_dis_base(const Domaine_dis_base &) override
const Domaine_dis_base & domaine_dis_base() const override
DoubleTab & valeurs() override
Returns the array of field values at the current time.
class Champ_base This class is the base of the fields hierarchy.
class Champ_front_base Base class for the hierarchy of boundary fields.
virtual const Frontiere_dis_base & frontiere_dis() const
Returns the discretized boundary associated with the field.
DoubleTab & valeurs_au_temps(double temps) override
Returns the values at the desired time.
class Cond_lim_base Base class for the hierarchy of classes that represent the different boundary con...
virtual Frontiere_dis_base & frontiere_dis()
Returns the discretized boundary to which the boundary conditions apply.
Champ_front_base & champ_front()
class Conds_lim This class represents a vector of boundary conditions.
Represents the constituent(s) of a fluid.
Convection_Diffusion_Concentration Special case of Convection_Diffusion_std.
SmallArrOfTID_t & chercher_elements(const DoubleTab &pos, SmallArrOfTID_t &elem, int reel=0) const
Searches for the elements containing the points whose coordinates are specified.
int nb_faces_elem(int=0) const
Returns the number of faces of type i of the geometric elements that make up the domain.
class Domaine_Cl_dis_base Domaine_Cl_dis_base objects represent discretized boundary conditions
int nb_cond_lim() const
Returns the number of boundary conditions.
const Cond_lim & les_conditions_limites(int) const
Returns the i-th boundary condition.
virtual const DoubleVect & face_surfaces() const
virtual double face_normales(int face, int comp) const
double xv(int num_face, int k) const
double volumes(int i) const
Frontiere_dis_base & frontiere_dis(int) override
Returns the i-th discrete boundary.
int elem_faces(int i, int j) const
Returns the index of the i-th face of element num_elem; the face numbering convention is.
int oriente_normale(int f, int e) const
int face_voisins(int num_face, int i) const
Returns the neighbouring element of num_face in direction i.
const Front_VF & front_VF(int i) const
const Nom & le_nom() const override
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
class Domaine_dis_base This class is the base of the hierarchy of discretized domains.
const Frontiere_dis_base & frontiere_dis(const Nom &) const
Returns the boundary of Name nom.
int rang_frontiere(const Nom &)
const Domaine & domaine() const
Class defining operators and methods for all reading operation in an input flow (file,...
class Equation_base The role of an equation is the calculation of one or more fields....
virtual const Milieu_base & milieu() const =0
virtual const RefObjU & get_modele(Type_modele type) const
virtual const Champ_Inc_base & inconnue() const =0
virtual Domaine_Cl_dis_base & domaine_Cl_dis()
Returns the discretized boundary condition domain associated with the equation.
Probleme_base & probleme()
Returns the problem associated with the equation.
virtual void fixer_nb_comp(int i)
Sets the number of components of the field.
const Nom & le_nom() const override
Returns the name of the field.
void nommer(const Nom &) override
Gives a name to the field.
: Post-processing class for Eulerian fields in MED format.
int ecrire_domaine(const Domaine &domaine, const int est_le_premier_post) override
Writing a mesh.
int initialize_by_default(const Nom &file_basename) override
Initializes the class with default parameters.
int ecrire_champ(const Domaine &domaine, const Noms &unite_, const Noms &noms_compo, int ncomp, double temps_, const Nom &id_du_champ, const Nom &id_du_domaine, const Nom &localisation, const Nom &nature, const DoubleTab &data) override
voir Format_Post_base::ecrire_champ
int num_premiere_face() const
virtual void trace_face_distant(const DoubleTab &, DoubleTab &) const
const Nom & le_nom() const override
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
int_t nb_faces() const
Returns the number of faces of the boundary.
class Frontiere_dis_base Class representing a discretized boundary.
const Frontiere & frontiere() const
Returns the associated geometric boundary.
const Domaine_dis_base & domaine_dis() const
const Nom & le_nom() const override
Returns the name of the geometric boundary.
static Objet_U & objet(const Nom &)
See Interprete_bloc::objet_global(). BM: the Interprete class is not the best place for this.
Milieu_base This class is the base of the (physical) medium hierarchy.
virtual const Equation_base & equation(const std::string &nom_inc) const
virtual const Champ_Don_base & conductivite() const
Returns the conductivity of the medium (const version).
virtual const Champ_Don_base & diffusivite() const
Returns the diffusivity of the medium (const version).
Base class for scalar turbulence models coupled to a Navier-Stokes convection-diffusion equation.
const Champ_Fonc_base & conductivite_turbulente() const
const Turbulence_paroi_scal_base & loi_paroi() const
Returns the scalar wall-law turbulence model (const version).
int loi_paroi_non_nulle() const
Returns whether a wall law is set (const version).
const Equation_base & equation() const
Returns the reference to the equation pointed to by MorEqn::mon_equation.
A character string (Nom) in uppercase.
class Nom: a character string for naming TRUST objects.
Nom & prefix(const char *const)
const Nom & le_nom() const override
Returns *this.
An array of character strings (VECT(Nom)).
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Class Pb_Conduction: represents a heat conduction problem with non-uniform rho and Cp:
class Probleme_base It is a Probleme_U that is not a coupling.
const Champ_base & get_champ(const Motcle &nom) const override
virtual const Equation_base & equation(int) const =0
static bool is_parallel()
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
void initialise(const Frontiere_t &, const Domaine_dis_base &, const Domaine_dis_base &)
SFichier is to the C++ ofstream class what Sortie is to the C++ ostream class.
Base class for output streams.
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
_SIZE_ dimension(int d) const
void resize(_SIZE_, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
const Objet_U & valeur() const
Base class for the hierarchy of scalar wall-law models computing turbulent quantities near walls....
virtual bool use_equivalent_distance() const
Give a boolean indicating if we need to use equivant distance by default we consider that we use the ...
const DoubleVects & equivalent_distance() const