TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Collision_Model_FT_base.cpp
1/****************************************************************************
2* Copyright (c) 2025, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <EFichier.h>
17#include <EcritureLectureSpecial.h>
18#include <Probleme_FT_Disc_gen.h>
19
20
21#include <type_traits>
22#include <Collision_Model_FT_base.h>
23
24// XD Collision_Model_FT_base objet_u Collision_Model_FT_base INHERITS_BRACE base for collision models for fluid
25// XD_CONT particle interaction
26Implemente_base_sans_constructeur(Collision_Model_FT_base,"Collision_Model_FT_base",Objet_U);
27
33{
34 Param p(que_suis_je());
35 set_param(p);
36 p.lire_avec_accolades_depuis(is);
37 return is;
38}
39
41{
42 Cerr << "Error::printOn is not implemented." << finl;
44 return os;
45}
46
48{
49 // could becom a param.dico
50 p.ajouter_non_std("collision_model", (this),Param::REQUIRED); // XD_ADD_P chaine(into=["hybrid_esi","breugem"])
51 // XD_CONT name of the collision model
52
53 // needs to be done like the bloc_convection schema. Or simplify the syntax into some standard Param
54 p.ajouter_non_std("detection_method", (this),Param::REQUIRED); // XD_ADD_P bloc_lecture
55 // XD_CONT method to detect collisions
56
57
58 p.ajouter("collision_duration", &collision_duration_, Param::REQUIRED); // XD_ADD_P double
59 // XD_CONT duration of the collision in seconds;
60
61 p.ajouter("activate_collision_before_impact", &is_collision_activated_before_impact_, Param::REQUIRED); // XD_ADD_P int
62 // XD_CONT activate collision before impact (1) or not (0)
63
64 p.ajouter("activation_distance_percentage_diameter", &activation_distance_percentage_diameter_, Param::REQUIRED); // XD_ADD_P double
65 // XD_CONT activation distance of the collision process as a percentage of the particle diameter
66
67 p.ajouter("force_on_two_phase_elem", &is_force_on_two_phase_elem_, Param::REQUIRED); // XD_ADD_P entier(into=[0,1],default=0)
68 // XD_CONT force on two phase elements (1) or not (0). Only valid for a single particle.
69}
70
72{
73 if (word=="collision_model")
74 {
75 Motcles words;
76 words.add("hybrid_esi");
77 words.add("breugem");
78 Motcle secondword;
79 is >> secondword;
80 Cerr << "Reading collision_model attributes: " << secondword << finl;
81 const int r = words.search(secondword);
82 switch(r)
83 {
84 case 0:
86 break;
87 case 1:
89 break;
90 default:
91 Cerr << "Error " << words << "was expected whereas " << secondword <<
92 " has been found."<< finl;
94 }
95 return 1;
96 }
97 else if (word=="detection_method")
98 {
99
100 Motcle openbrace ="{";
101 Motcle closedbrace="}";
102 Motcle secondword;
103 is >> secondword;
104 if (secondword==openbrace)
105 {
106 is >> secondword;
107
108 Motcles words;
109 words.add("check_all");
110 words.add("verlet");
111 words.add("lc_verlet");
112 const int r = words.search(secondword);
113 switch(r)
114 {
115 case 0:
117 break;
118 case 1:
120 break;
121 case 2:
123 break;
124 default:
125 Cerr << "Error " << words << "was expected whereas "
126 << secondword << " has been found."<< finl;
128 }
129
130 is >> secondword;
131 while (secondword != closedbrace)
132 {
133 Motcles otherwords;
134 otherwords.add("detection_thickness_Verlet");
135 otherwords.add("nb_pas_dt_max_Verlet");
136 int rang2 = otherwords.search(secondword);
137 switch(rang2)
138 {
139 case 0:
141 break;
142 case 1:
143 is >> nb_dt_max_Verlet_;
144 break;
145 default:
146 Cerr << "Collision_Model_FT_base::lire_motcle_non_standard\n"
147 << " options of collision_detection are:\n"
148 << otherwords;
150 }
151 is >> secondword;
152 }
153 }
154 return 1;
155 }
156 else
157 {
158 Cerr << word << " is not a keyword understood by " << que_suis_je() <<
159 " in lire_motcle_non_standard"<< finl;
161 }
162 return -1;
163}
164
166{
167 const int nb_boundaries=2*dimension;
168 F_old_.resize(nb_particles_tot_,nb_particles_tot_+nb_boundaries);
169 F_now_.resize(nb_particles_tot_,nb_particles_tot_+nb_boundaries);
170 e_eff_.resize(nb_particles_tot_,nb_particles_tot_+nb_boundaries);
171 Cerr << "WARNING: Collision_Model_FT_base::reset of F_old_, F_now_, "
172 "lagrangian_contact_forces_ and e_eff_." << finl;
173}
174
176{
177 Nom readword;
178 const int format_xyz = EcritureLectureSpecial::is_lecture_special();
179
180 is >> readword;
181 if (readword != que_suis_je())
182 {
183 Cerr << "Error in Collision_Model_FT_base::reprendre\n";
184 Cerr << "We was expecting " << que_suis_je();
185 Cerr << "\n We found " << readword << finl;
187 }
188 is >> nb_particles_tot_;
191 if (format_xyz)
192 {
193 for (int i=0; i<F_old_.dimension(0); i++)
194 for (int j=0; j<F_old_.dimension(1); j++)
195 is>>F_old_(i,j);
196 for (int i=0; i<e_eff_.dimension(0); i++)
197 for (int j=0; j<e_eff_.dimension(1); j++)
198 is>>e_eff_(i,j);
199 }
200 else
201 {
202 is>>F_old_;
203 is>>e_eff_;
204 }
205 return 1;
206}
207
209{
210 int special, afaire;
211 const int format_xyz = EcritureLectureSpecial::is_ecriture_special(special, afaire);
212 int bytes = 0;
213 if (format_xyz)
214 {
216 {
217 os << Nom(que_suis_je()) << finl;
218 os << nb_particles_tot_ << finl;
219 for (int i=0; i<F_old_.dimension(0); i++)
220 for (int j=0; j<F_old_.dimension(1); j++)
221 os<<F_old_(i,j);
222 for (int i=0; i<e_eff_.dimension(0); i++)
223 for (int j=0; j<e_eff_.dimension(1); j++)
224 os<<e_eff_(i,j);
225 }
226 return 0;
227 }
228 else
229 {
230 os << que_suis_je() << finl;
231 os << nb_particles_tot_ << finl;
232 os << F_old_;
233 bytes += 8 * F_old_.size_array();
234 os << e_eff_;
235 bytes += 8 * e_eff_.size_array();
236 return bytes;
237 }
238}
239
241 const int nb_particles_tot,
242 const Navier_Stokes_FT_Disc& ns,
243 const Transport_Interfaces_FT_Disc& eq_transport,
244 const Schema_Comm& schema_comm_FT)
245{
246 set_geometric_parameters(domain_vdf);
247 set_nb_particles_tot(nb_particles_tot);
248 set_nb_real_particles(nb_particles_tot);
251 const Fluide_Diphasique& two_phase_elem=ns.fluide_diphasique();
252 const int id_solid_phase=1-two_phase_elem.get_id_fluid_phase();
253 const Solid_Particle_base& solid_particle=ref_cast(Solid_Particle_base,
254 two_phase_elem.fluide_phase(id_solid_phase));
255 const double& diameter=solid_particle.get_equivalent_diameter();
256 set_activation_distance(diameter);
258 associate_transport_equation(eq_transport);
259
260 if (is_LC_activated())
261 set_LC_zones(domain_vdf,schema_comm_FT);
262
263 set_spring_properties(solid_particle);
264
265 if ((F_old_.dimension(0)!=nb_particles_tot) ||
266 (F_now_.dimension(0)!=nb_particles_tot) )
267 reset();
268
269 return 1;
270}
271
278
280{
282 {
283 const double mass_sphere = solid_particle.get_mass();
284 const double e_dry = solid_particle.get_e_dry();
285 const double mass_eff_part_part = mass_sphere/2;
286 const double mass_eff_wall_part = mass_sphere;
287
290
292 {
293 damper_breugem_part_part_ = compute_damper_breugem(mass_eff_part_part,e_dry);
294 damper_breugem_wall_part_ = compute_damper_breugem(mass_eff_wall_part,e_dry);
295 }
296 }
297}
298
300{
301 const Transport_Interfaces_FT_Disc& eq = ref_cast(Transport_Interfaces_FT_Disc,equation);
302 refequation_transport_ = eq;
303}
304
306{
307 DoubleVect offset_values(2*dimension);
308
310 {
311 case 0:
312 offset_values=0;
313 break;
314 case 1:
315 if (activation_distance_>0) offset_values=activation_distance_;
316 break;
317 default:
318 Cerr << "Collision_Model_FT_base::compute_fictive_wall_coordinates error" <<finl;
320 break;
321 }
322
323 // an offset is computed for the walls to activate the collision process before the impact
324 fictive_wall_coordinates_(0) = origin_(0) - radius + offset_values(0);
325 fictive_wall_coordinates_(1) = origin_(1) - radius + offset_values(1);
326 fictive_wall_coordinates_(2) = origin_(2) - radius + offset_values(2);
327 fictive_wall_coordinates_(3) = origin_(0) + domain_dimensions_(0) + radius - offset_values(3);
328 fictive_wall_coordinates_(4) = origin_(1) + domain_dimensions_(1) + radius - offset_values(4);
329 fictive_wall_coordinates_(5) = origin_(2) + domain_dimensions_(2) + radius - offset_values(5);
330
331 Cerr << "fictive_wall_coordinates\n" << fictive_wall_coordinates_ << finl;
332}
333
334/*! @brief Recover the geometric parameters of the domain:
335 * number of nodes in each direction
336 * origin of the domain
337 * dimensions of the domain
338 */
340{
341 const Domaine& domain = domaine_vdf.domaine();
342 const DoubleTab BB=domain.getBoundingBox();
343 const Bords& bords=domain.faces_bord();
344 DoubleVect NiNj(dimension); // NiNj=(NyNz NxNz NxNy )
346
347 // 1. Number of nodes per direction
348 NiNj=0;
349 for (int i=0; i<bords.nb_bords(); i++)
350 {
351 int nb_boundary_faces = Process::check_int_overflow(mp_sum(ref_cast(Frontiere,bords(i)).nb_faces()));
352 int nb_boundary_faces_local=ref_cast(Frontiere,bords(i)).nb_faces();
353 if (nb_boundary_faces_local>0)
354 {
355 int face1=ref_cast(Frontiere,bords(i)).num_premiere_face();
356 int orientation_face1=domaine_vdf.orientation(face1);
357 NiNj(orientation_face1)=nb_boundary_faces;
358 }
359 }
360 long long NxNy= static_cast<int>(mp_max(NiNj(2))) ;
361 long long NxNz= static_cast<int>(mp_max(NiNj(1)));
362 long long NyNz= static_cast<int>(mp_max(NiNj(0)));
363
364 int Nx,Ny,Nz;
365
366 Ny= NxNz>0 ? static_cast<int>(sqrt(NxNy*NyNz/NxNz)) : 0; // nb elem in the y-direction
367 Nz= NxNy>0 ? static_cast<int>((NxNz*Ny/NxNy)) : 0; // nb elem in the z-direction, WARNING: operations order matter because Nz is an integer
368 Nx= Ny>0 ? static_cast<int>(NxNy/Ny) : 0; // nb elem in the x-direction
369
370 nb_nodes_(0)=Nx++; // nb nodes in the x-direction
371 nb_nodes_(1)=Ny++; // nb nodes in the y-direction
372 nb_nodes_(2)=Nz++; // nb nodes in the z-direction
373
374 // 2. Origin and Domain_dimensions
375 DoubleVect Origin(dimension);
376 DoubleVect Domain_dimensions(dimension);
377 Origin=0.;
378 Domain_dimensions=0.;
379
380 for (int j=0; j<dimension; j++)
381 {
382 double min_ = mp_min(BB(j,0));
383 double max_ = mp_max(BB(j,1));
384
385 Origin(j)=min_;
386 Domain_dimensions(j)=max_-min_;
387 }
388
389 set_origin(Origin);
390 set_domain_dimensions(Domain_dimensions);
391
392 Cerr << "Origin " << Origin << finl;
393 Cerr << "Domain length" << Domain_dimensions << finl;
394 Cerr << "Nx Ny Nz " << nb_nodes_ << finl;
395}
396
397/*! @brief Check if two particles have the same ID
398 * Very important function to stop computation if
399 * two particles coalesce.
400 */
402{
403 int flag =0;
404 ArrOfInt copy_vector(vector);
405 const int size = copy_vector.size_array();
406 copy_vector.ordonne_array();
407 for (int i = 0; i < size-1; i++)
408 {
409 if (copy_vector(i)==copy_vector(i+1))
410 {
411 flag = 1;
412 Cerr << copy_vector(i) << " is duplicate !!" << finl ;
413 }
414 }
415 return flag;
416}
417
418
419/* @brief we send the list of real particles to proc from lower zones
420 */
421ArrOfInt send_receive_list_id_particles(ArrOfInt& list_id_real_particles_to_send,
422 const ArrOfInt& list_lower_zone,
423 const Schema_Comm& schema_comm)
424{
425 ArrOfInt list_id_particle_recv;
426 list_id_particle_recv.resize_array(0);
427 //int nb_elem_recv=0;
428 const int nb_real_particles_to_send=list_id_real_particles_to_send.size_array();
429
430 schema_comm.begin_comm();
431
432 for (int ind_pe_dest=0; ind_pe_dest<list_lower_zone.size_array(); ind_pe_dest++)
433 {
434 int PE_dest=list_lower_zone(ind_pe_dest);
435 for(int ind_particle=0; ind_particle<nb_real_particles_to_send; ind_particle++)
436 {
437 const int id_particle=list_id_real_particles_to_send(ind_particle);
438 assert(PE_dest!=Process::me());
439 schema_comm.send_buffer(PE_dest) << id_particle;
440 }
441 }
442
443 schema_comm.echange_taille_et_messages();
444
445 const ArrOfInt& recv_pe_list = schema_comm.get_recv_pe_list();
446 const int nb_recv_pe = recv_pe_list.size_array();
447 for (int i=0; i<nb_recv_pe; i++)
448 {
449 const int pe_source = recv_pe_list[i];
450 Entree& buffer = schema_comm.recv_buffer(pe_source);
451 while(1)
452 {
453 int id_particle_recv=-1;
454 buffer >> id_particle_recv;
455 if (buffer.eof())
456 break;
457 if (id_particle_recv<0)
459 //nb_elem_recv++;
460 list_id_particle_recv.append_array(id_particle_recv);
461 }
462 }
463 schema_comm.end_comm();
464
465 return list_id_particle_recv;
466}
467
468
470 eq_ns,const Transport_Interfaces_FT_Disc& eq_transport)
471{
472 ArrOfInt list_particles_to_check_LC;
473 const ArrOfInt& gravity_center_elem=eq_transport.get_gravity_center_elem();
474 const Domaine_VF& domain_vf=ref_cast(Domaine_VF,eq_ns.domaine_dis());
475 const int& nb_elem=domain_vf.nb_elem();
476 const Maillage_FT_Disc& mesh=eq_transport.maillage_interface();
477 const Schema_Comm& schema_comm=mesh.get_schema_comm_FT();
478 const DoubleTab& particles_velocity=eq_transport.get_particles_velocity();
479 const DoubleTab& particles_position=eq_transport.get_particles_position();
480 const Fluide_Diphasique& two_phase_elem=eq_ns.fluide_diphasique();
481 const int id_solid=1-two_phase_elem.get_id_fluid_phase();
482 const auto& solid_particle=ref_cast(Solid_Particle_base,two_phase_elem.fluide_phase(id_solid));
483 const double& radius=solid_particle.get_equivalent_radius();
484 const Schema_Temps_base& time_scheme=eq_ns.schema_temps();
485 const double& time_step=time_scheme.pas_de_temps();
486
487 Cerr << "Update of Verlet tables - " ;
488 // Step 1 : update of Linked Cells (for more info on the method, see X. Fang et al.,
489 // J. Sound Vib., 2007).
490 // Here, each linked cell match a CPU domain. We seed the id of real particles to LC
491 // from lower zones (to receive LC from upper zones)
493 {
495 list_real_particles_.resize_array(0);
496 for (int particle=0; particle<nb_particles_tot_; particle++)
497 {
498 if (gravity_center_elem(particle)>-1 && gravity_center_elem(particle)<nb_elem)
499 {
500 list_real_particles_.append_array(particle);
502 }
503 }
505
506 //Process::barrier(); // we wait that all procs have updated their list to do the exchange
507 ArrOfInt list_virtual_particles;
508 const ArrOfInt& list_lower_zone=get_list_lower_zone();
509 list_virtual_particles=send_receive_list_id_particles(list_real_particles_,
510 list_lower_zone,
511 schema_comm);
512 if (nb_real_particles_>0)
513 {
514 Cerr << "list_real_particles_ " << list_real_particles_<< finl;
515 Cerr << "list_virtual_particles " << list_virtual_particles<< finl;
516 list_particles_to_check_LC.resize(list_real_particles_.size_array()+
517 list_virtual_particles.size_array());
518 for (int k=0; k<list_real_particles_.size_array()
519 +list_virtual_particles.size_array(); k++)
520 {
521 if (k<list_real_particles_.size_array()) list_particles_to_check_LC(k)=
523 else list_particles_to_check_LC(k)=
524 list_virtual_particles(k-list_real_particles_.size_array());
525 }
526 Cerr << "list_particles_to_check_LC " << list_particles_to_check_LC<< finl; // do not sort the list
527 }
528 }
529 // ETAPE B : update of Verlet tables
530 // we compute the distance between particles and we save the pairs that are within
531 // the distance detection_thickness_Verlet_. I usually define it as 30% of the particle
532 // diameter in the data file.
533 // For Verlet table without LC, we test all particle pairs
534 // For Verlet method with LC, for all real particles, we test all particles
535 // pairs from the upper zone (proc domain + upper procs domain)
536 double max_vi_glob=0;
537 double max_vi=0.;
538 if (nb_real_particles_>0)
539 {
542
543 compute_Verlet_tables(particles_position,
544 particles_velocity,
545 max_vi,
546 radius,
547 list_particles_to_check_LC);
548 }
549 max_vi_glob=mp_max(max_vi); // with the linked cell method, we compute the max.
550 // With only Verlet method,
551 // there is no need to, but max_vi=mp_max(max_vi) for each proc.
552 // Computing the next Verlet table update time step based on the maximum velocity
553 // of a particle in the domain
554 int deltat_compute_min = (max_vi_glob>0) ?
555 static_cast<int>(floor((detection_thickness_Verlet_/(2*max_vi_glob))/
556 time_step)) :
558
559 nb_dt_compute_Verlet_=std::min(deltat_compute_min,nb_dt_max_Verlet_);
560 Cerr << "Next update in " <<nb_dt_compute_Verlet_ << " time steps." << finl;
562 // Cerr to check if Verlet tables are correctly filled
563 if (nb_particles_tot_<20)
564 {
565 for (int ind_part_i=0; ind_part_i <nb_real_particles_; ind_part_i++)
566 {
567 Cerr << "Verlet_tables_["<<ind_part_i<<"].size() " << Verlet_tables_[ind_part_i].size() << " -- ";
568 for (int ind_part_j=0; ind_part_j<Verlet_tables_[ind_part_i].size(); ind_part_j++)
569 Cerr << " " << Verlet_tables_[ind_part_i][ind_part_j];
570 Cerr << finl;
571 }
572 }
573}
574
575int Collision_Model_FT_base::get_last_id(const ArrOfInt& list_particles_to_check_LC)
576{
578 Process::exit("Collision_Model_FT_base::get_last_id Should not be in here!");
580 return nb_particles_tot_;
582 return(list_particles_to_check_LC.size_array());
583 return 0;
584}
585
586
587int Collision_Model_FT_base::get_id(const ArrOfInt& list_particle, const int ind_id_particle)
588{
590 Process::exit("Collision_Model_FT_base::get_id Should not be in here!");
592 return(ind_id_particle);
594 return(list_particle(ind_id_particle));
595 else
596 Process::exit("Collision_Model_FT_base::get_id unkwnown detection_method_!");
597 return 0;
598}
599
600int Collision_Model_FT_base::get_particle_j(const int ind_particle_i, const int ind_particle_j)
601{
603 return(ind_particle_j);
606 return (Verlet_tables_[ind_particle_i][ind_particle_j]);
607 return 0;
608}
609
610int Collision_Model_FT_base::get_nb_particles_j(const int ind_particle_i) const
611{
613 return (nb_particles_tot_+2*dimension);
616 return (Verlet_tables_[ind_particle_i].size());
617 return 0;
618}
619
620int Collision_Model_FT_base::get_particle_i(const int ind_particle_i)
621{
623 list_real_particles_(ind_particle_i) : ind_particle_i);
624}
625
626int Collision_Model_FT_base::get_ind_start_particles_j(const int ind_particle_i) const
627{
629 (ind_particle_i+1) : 0);
630}
631
632
633void Collision_Model_FT_base::compute_Verlet_tables(const DoubleTab& particles_position,
634 const DoubleTab& particles_velocity,
635 double& max_vi,
636 const double& radius,
637 const ArrOfInt& list_particles_to_check_LC)
638{
639 int last_id = get_last_id(list_particles_to_check_LC);
640 for (int ind_id_particle_i=0; ind_id_particle_i< nb_real_particles_; ind_id_particle_i++)
641 {
642 int id_particle_i=get_id(list_particles_to_check_LC,ind_id_particle_i);
643 const double vi=fabs(sqrt(
644 pow(particles_velocity(id_particle_i,0),2) +
645 pow(particles_velocity(id_particle_i,1),2) +
646 pow(particles_velocity(id_particle_i,2),2)));
647 if (vi>max_vi)
648 max_vi=vi;
649 // particle-particle distance
650 for (int ind_id_particle_j=ind_id_particle_i+1; ind_id_particle_j< last_id; ind_id_particle_j++)
651 {
652 int id_particle_j= get_id(list_particles_to_check_LC, ind_id_particle_j);
653 double dij=sqrt(
654 pow(particles_position(id_particle_j,0)-particles_position(id_particle_i,0),2) +
655 pow(particles_position(id_particle_j,1)-particles_position(id_particle_i,1),2) +
656 pow(particles_position(id_particle_j,2)-particles_position(id_particle_i,2),2));
657
658 if ((dij-2*radius)<=detection_thickness_Verlet_)
659 Verlet_tables_[ind_id_particle_i].add(id_particle_j);
660
661 }
662
663 // wall-particle distance
664 for (int ind_wall=0; ind_wall<2*dimension; ind_wall++)
665 {
666 const int ori = ind_wall < dimension ? ind_wall : ind_wall - dimension;
667 const double dij=fabs(fictive_wall_coordinates_(ind_wall)-
668 particles_position(id_particle_i,ori));
669
670 if ((dij-2*radius)<=detection_thickness_Verlet_)
671 Verlet_tables_[ind_id_particle_i].add(nb_particles_tot_+ind_wall);
672 }
673 }
674}
675
676
678 DoubleTab& dU,
679 const int& particle,
680 const int& neighbor,
681 const DoubleTab& particles_position,
682 const DoubleTab& particles_velocity,
683 const bool is_particle_particle_collision)
684{
685 if (is_particle_particle_collision)
686 {
687 for (int d = 0; d < dimension; d++)
688 {
689 dX(d) = particles_position(particle, d) - particles_position(neighbor, d);
690 dU(d) = particles_velocity(particle, d) - particles_velocity(neighbor, d);
691 }
692 }
693 else
694 {
695 int ind_wall = neighbor - nb_particles_tot_;
696 int ori = ind_wall < dimension ? ind_wall : ind_wall - dimension;
697 dX(ori) = particles_position(particle, ori) - fictive_wall_coordinates_(ind_wall);
698 for (int d = 0; d < dimension; d++)
699 dU(d) = particles_velocity(particle, d);
700 }
701}
702
704 const double& next_dist_int,
705 const DoubleTab& norm,
706 const DoubleTab& dUn,
707 const int& particle_i,
708 const int& particle_j,
709 const int& is_compression_step,
710 const double& is_collision_part_part)
711{
712 DoubleTab force_contact(dimension);
713
714 if (collision_model_==Collision_model::HYBRID_ESI) // see Hamidi et al., IJMF, 2023.
715 {
716 const double e_eff_particle = is_compression_step ? 1 : e_eff_(particle_i, particle_j);
717 const double stiffness = is_collision_part_part ? stiffness_breugem_part_part_:
719 for (int d = 0; d < dimension; d++)
720 force_contact(d)= -pow(e_eff_particle,2) * stiffness * next_dist_int * norm(d);
721 }
722 else if (collision_model_==Collision_model::BREUGEM) // See. W-P. Breugem, 2010.
723 {
724 const double stiffness = is_collision_part_part ? stiffness_breugem_part_part_:
726 const double damper = is_collision_part_part ? damper_breugem_part_part_:
728 for (int d = 0; d < dimension; d++)
729 force_contact(d)= -stiffness*next_dist_int*norm(d) -damper*dUn(d);
730 }
731 else
732 Process::exit("Collision_Model_FT_base::compute_contact_force unknown collision_model_");
733
734 return force_contact;
735}
736
738 const DoubleTab& volumic_phase_indicator_function,
739 const Domaine_VF& domain_vf,
740 const IntTab& particles_eulerian_id_number,
741 DoubleTab& contact_force_source_term)
742{
743 Process::exit("Collision_Model_FT_base::discretize_contact_forces_eulerian_field "
744 "not coded for particles of arbitrary shape");
745}
746
748{
750 return false;
751 return true;
752}
753
755{
757 return true;
758 return false;
759}
760
761void Collision_Model_FT_base::set_LC_zones(const Domaine_VF& domain_vf, const Schema_Comm& schema_com)
762{
763 int nsup=0;
764 int ninf=0;
765
766 int nb_joints=domain_vf.nb_joints();
767
768 double x0 = domain_vf.xp(0,0);
769 double y0 = domain_vf.xp(0,1);
770 double z0 = domain_vf.xp(0,2);
771 double epsilon=1e-10;
772 const int nb_elems=domain_vf.nb_elem();
773 const int nb_elems_tot=domain_vf.nb_elem_tot();
774
775 Cerr << "number or reals elements " << nb_elems << finl;
776 Cerr << "total number of elements " << nb_elems_tot << finl;
777 Cerr << "(x0 y0 z0) = (" << x0 << " " << y0 << " " << z0 << ")" << finl;
778 Cerr << "joints number " << nb_joints << finl;
779
780 // Firstly, every proc send coordinates of its first elem to other procs
781 DoubleTabFT list_coord_recv(0,dimension);
782 IntTabFT list_pe_recv(0);
783 Cerr << "list_coord_recv.dimensions " << list_coord_recv.dimension(0) << " "
784 << list_coord_recv.dimension(1) << finl;
785 int nb_elem_recv=0;
786
787 schema_com.begin_comm();
788
789 for (int ind_pe_dest=0; ind_pe_dest<nb_joints; ind_pe_dest++)
790 {
791 const Joint& joint_temp = domain_vf.joint(ind_pe_dest);
792 const int pe_dest = joint_temp.PEvoisin();
793 assert(pe_dest!=Process::me());
794 schema_com.send_buffer(pe_dest) << x0 << y0 << z0;
795 }
796
797 schema_com.echange_taille_et_messages();
798
799 const ArrOfInt& recv_pe_list = schema_com.get_recv_pe_list();
800 const int nb_recv_pe = recv_pe_list.size_array();
801 for (int i=0; i<nb_recv_pe; i++)
802 {
803 const int pe_source = recv_pe_list[i];
804 Entree& buffer = schema_com.recv_buffer(pe_source);
805 while(1)
806 {
807 double x0_rcv=-1, y0_rcv=-1, z0_rcv=-1;
808 buffer >> x0_rcv >> y0_rcv >> z0_rcv;
809 if (buffer.eof())
810 break;
811 nb_elem_recv++;
812 list_coord_recv.append_line(x0_rcv,y0_rcv,z0_rcv);
813 list_pe_recv.append_line(pe_source);
814 }
815 }
816
817 schema_com.end_comm();
818
819 list_coord_recv.resize(nb_elem_recv,dimension);
820 list_pe_recv.resize(nb_elem_recv);
821
822 if (nb_joints != nb_elem_recv) Process::exit("EB : Collision_Model_FT_base::"
823 "set_LC_zones -- erreur identification du 1er element"
824 " des procs de la zone de joint.");
825 for(int ind_pe=0; ind_pe<nb_elem_recv; ind_pe++)
826 {
827 const int pe_voisin = list_pe_recv(ind_pe);
828 double x0_joint = list_coord_recv(ind_pe,0);
829 double y0_joint = list_coord_recv(ind_pe,1);
830 double z0_joint = list_coord_recv(ind_pe,2);
831
832 if ( y0_joint>y0 || (fabs(y0_joint-y0)<epsilon && x0_joint>x0) ||
833 ( fabs(x0_joint-x0) < epsilon && fabs(y0_joint-y0)<epsilon && (z0_joint>z0)) )
834 list_upper_zone_.append_array(pe_voisin), nsup++;
835 if ( y0_joint<=y0 && (fabs(y0_joint-y0)>=epsilon || x0_joint<=x0)
836 && ( fabs(x0_joint-x0) >= epsilon || fabs(y0_joint-y0)>=epsilon
837 || (z0_joint<=z0)) )
838 list_lower_zone_.append_array(pe_voisin), ninf++;
839
840 }
841
842 list_upper_zone_.resize_array(nsup);
843 list_lower_zone_.resize_array(ninf);
844
845 Cerr << "list_upper_zone_ " << list_upper_zone_ << finl;
846 Cerr << "list_lower_zone_ " << list_lower_zone_ << finl;
847 Cerr << "max number of upper zone = " << mp_max(nsup) << finl;
848 Cerr << "max number of lower zone = " << mp_max(ninf) << finl;
849}
850
851void Collision_Model_FT_base::add_collision(const int part_i, const int part_j, const bool is_part_part_collision)
852{
853 const double contrib=is_part_part_collision? 1 : .2; // for wall_particle_collision we add .2 (for post-processing)
854 if (part_i<nb_particles_tot_)
855 particles_collision_number_(part_i)+=contrib;
856 if (part_j<nb_particles_tot_)
857 particles_collision_number_(part_i)+=contrib;
858}
859
int nb_bords() const
Definition Bords.h:39
: class Collision_Model_FT
void compute_fictive_wall_coordinates(const double &radius)
void set_activation_distance(const double &diameter)
double compute_damper_breugem(const double &mass_eff, const double &e_dry)
int sauvegarder(Sortie &os) const override
Sauvegarde d'un Objet_U sur un flot de sortie Methode a surcharger.
void associate_transport_equation(const Equation_base &equation)
void set_origin(DoubleVect &Origin)
void set_geometric_parameters(const Domaine_VDF &domaine_vdf)
Recover the geometric parameters of the domain: number of nodes in each direction origin of the domai...
virtual void discretize_contact_forces_eulerian_field(const DoubleTab &volumic_phase_indicator_function, const Domaine_VF &domain_vf, const IntTab &particles_eulerian_id_number, DoubleTab &contact_force_source_term)=0
int get_particle_i(const int ind_particle_i)
int check_for_duplicates(ArrOfInt &vector)
Check if two particles have the same ID Very important function to stop computation if two particles ...
int get_ind_start_particles_j(const int ind_particle_i) const
int get_nb_particles_j(const int ind_particle_i) const
void add_collision(const int part_i, const int part_j, const bool is_part_part_collision)
double compute_stiffness_breugem(const double &mass_eff, const double &e_dry)
int preparer_calcul(const Domaine_VDF &domain_vdf, const int nb_particles_tot, const Navier_Stokes_FT_Disc &ns, const Transport_Interfaces_FT_Disc &eq_transport, const Schema_Comm &schema_comm_FT)
void set_domain_dimensions(DoubleVect &Longueurs)
void research_collision_pairs_Verlet(const Navier_Stokes_FT_Disc &eq_ns, const Transport_Interfaces_FT_Disc &eq_transport)
int lire_motcle_non_standard(const Motcle &, Entree &) override
Lecture des parametres de type non simple d'un objet_U a partir d'un flot d'entree.
int get_id(const ArrOfInt &list_particle, const int ind_id_particle)
const ArrOfInt & get_list_lower_zone() const
int get_particle_j(const int ind_particle_i, const int ind_particle_j)
void set_nb_particles_tot(int nb_particles_tot)
void set_spring_properties(const Solid_Particle_base &solid_particle)
int get_last_id(const ArrOfInt &list_particles_to_check_LC)
void set_LC_zones(const Domaine_VF &domaine_vf, const Schema_Comm &schema_com)
int reprendre(Entree &is) override
Reprise d'un Objet_U sur un flot d'entree Methode a surcharger.
DoubleTab compute_contact_force(const double &next_dist_int, const DoubleTab &norm, const DoubleTab &dUn, const int &particle_i, const int &particle_j, const int &is_compression_step, const double &is_collision_part_part)
void compute_dX_dU(DoubleTab &dX, DoubleTab &dU, const int &particle, const int &neighbor, const DoubleTab &particles_position, const DoubleTab &particles_velocity, const bool is_particle_particle_collision)
void set_nb_real_particles(int nb_real_particles)
void set_param(Param &p) const override
void compute_Verlet_tables(const DoubleTab &particles_position, const DoubleTab &particles_velocity, double &max_vi, const double &radius, const ArrOfInt &list_particles_to_check_LC)
Bords_t & faces_bord()
Definition Domaine.h:198
DoubleTab getBoundingBox() const
Definition Domaine.cpp:884
class Domaine_VDF
Definition Domaine_VDF.h:64
int orientation(int) const override
inline DoubleVect& Domaine_VDF::porosite_face() {
class Domaine_VF
Definition Domaine_VF.h:44
int nb_joints() const
Definition Domaine_VF.h:65
const Joint & joint(int i) const
Definition Domaine_VF.h:105
double xp(int num_elem, int k) const
Definition Domaine_VF.h:77
int nb_elem_tot() const
const Domaine & domaine() const
static int is_ecriture_special(int &special, int &a_faire)
indique si le format special a ete demande en lecture active par sauvegarde xyz .
static int is_lecture_special()
indique si le format special a ete demande en lecture active par reprise xyz .
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual int eof()
Definition Entree.cpp:256
classe Equation_base Le role d'une equation est le calcul d'un ou plusieurs champs....
Schema_Temps_base & schema_temps()
Renvoie le schema en temps associe a l'equation.
Domaine_dis_base & domaine_dis()
Renvoie le domaine discretise associe a l'equation.
const Fluide_Incompressible & fluide_phase(int la_phase) const
const int & get_id_fluid_phase() const
int PEvoisin() const
Definition Joint.h:49
: class Maillage_FT_Disc Cette classe decrit un maillage:
const Schema_Comm & get_schema_comm_FT() const
Une chaine de caractere (Nom) en majuscules.
Definition Motcle.h:26
Un tableau d'objets de la classe Motcle.
Definition Motcle.h:63
int search(const Motcle &t) const
Definition Motcle.cpp:321
virtual const Fluide_Diphasique & fluide_diphasique() const
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
classe Objet_U Cette classe est la classe de base des Objets de TRUST
Definition Objet_U.h:73
friend class Entree
Definition Objet_U.h:76
static int dimension
Definition Objet_U.h:99
friend class Sortie
Definition Objet_U.h:75
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
@ REQUIRED
Definition Param.h:115
void ajouter_non_std(const char *keyword, const Objet_U *value, Param::Nature nat=Param::OPTIONAL)
Register a keyword handled by Objet_U::lire_motcle_non_standard.
Definition Param.cpp:489
static double mp_min(double)
Definition Process.cpp:386
static int check_int_overflow(trustIdType)
Definition Process.cpp:428
static double mp_max(double)
Definition Process.cpp:376
static double mp_sum(double)
Calcule la somme de x sur tous les processeurs du groupe courant.
Definition Process.cpp:146
static int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
static int je_suis_maitre()
renvoie 1 si on est sur le processeur maitre du groupe courant (c'est a dire me() == 0),...
Definition Process.cpp:86
void echange_taille_et_messages() const
Cette methode lance l'echange de donnees entre tous les processeurs.
Sortie & send_buffer(int num_PE) const
renvoie le buffer correspondant au processeur num_PE pour y entasser des donnees a envoyer.
void end_comm() const
Vide les buffers et libere les ressources: on a fini de lire les donnees recues dans les buffers.
Entree & recv_buffer(int num_PE) const
renvoie le buffer correspondant au processeur num_PE pour y lire les donnees recues.
const ArrOfInt & get_recv_pe_list() const
void begin_comm() const
Reserve les buffers de comm pour une nouvelle communication.
class Schema_Temps_base
double pas_de_temps() const
Renvoie le pas de temps (delta_t) courant.
: class Solid_Particle
const double & get_e_dry() const
const double & get_mass() const
const double & get_equivalent_diameter() const
Classe de base des flux de sortie.
Definition Sortie.h:52
void append_array(_TYPE_ valeur)
_SIZE_ size_array() const
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
void ordonne_array()
void resize(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTArray.h:156
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
void append_line(_TYPE_)
Definition TRUSTTab.tpp:213
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
const Maillage_FT_Disc & maillage_interface() const
const ArrOfInt & get_gravity_center_elem() const
const DoubleTab & get_particles_velocity() const
const DoubleTab & get_particles_position() const