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 p.ajouter_non_std("collision_model", (this),Param::REQUIRED); // XD_ADD_P chaine
50 // XD_CONT name of the collision model
51 p.ajouter_non_std("detection_method", (this),Param::REQUIRED); // XD_ADD_P chaine
52 // XD_CONT method to detect collisions
53 p.ajouter("collision_duration", &collision_duration_, Param::REQUIRED); // XD_ADD_P double
54 // XD_CONT duration of the collision in seconds;
55 p.ajouter("activate_collision_before_impact", &is_collision_activated_before_impact_, Param::REQUIRED); // XD_ADD_P int
56 // XD_CONT activate collision before impact (1) or not (0)
57 p.ajouter("activation_distance_percentage_diameter", &activation_distance_percentage_diameter_, Param::REQUIRED); // XD_ADD_P double
58 // XD_CONT activation distance of the collision process as a percentage of the particle diameter
59 p.ajouter("force_on_two_phase_elem", &is_force_on_two_phase_elem_, Param::REQUIRED); // XD_ADD_P int
60 // XD_CONT force on two phase elements (1) or not (0). Only valid for a single particle.
61}
62
64{
65 if (word=="collision_model")
66 {
67 Motcles words;
68 words.add("hybrid_esi");
69 words.add("breugem");
70 Motcle secondword;
71 is >> secondword;
72 Cerr << "Reading collision_model attributes: " << secondword << finl;
73 const int r = words.search(secondword);
74 switch(r)
75 {
76 case 0:
78 break;
79 case 1:
81 break;
82 default:
83 Cerr << "Error " << words << "was expected whereas " << secondword <<
84 " has been found."<< finl;
86 }
87 return 1;
88 }
89 else if (word=="detection_method")
90 {
91
92 Motcle openbrace ="{";
93 Motcle closedbrace="}";
94 Motcle secondword;
95 is >> secondword;
96 if (secondword==openbrace)
97 {
98 is >> secondword;
99
100 Motcles words;
101 words.add("check_all");
102 words.add("verlet");
103 words.add("lc_verlet");
104 const int r = words.search(secondword);
105 switch(r)
106 {
107 case 0:
109 break;
110 case 1:
112 break;
113 case 2:
115 break;
116 default:
117 Cerr << "Error " << words << "was expected whereas "
118 << secondword << " has been found."<< finl;
120 }
121
122 is >> secondword;
123 while (secondword != closedbrace)
124 {
125 Motcles otherwords;
126 otherwords.add("detection_thickness_Verlet");
127 otherwords.add("nb_pas_dt_max_Verlet");
128 int rang2 = otherwords.search(secondword);
129 switch(rang2)
130 {
131 case 0:
133 break;
134 case 1:
135 is >> nb_dt_max_Verlet_;
136 break;
137 default:
138 Cerr << "Collision_Model_FT_base::lire_motcle_non_standard\n"
139 << " options of collision_detection are:\n"
140 << otherwords;
142 }
143 is >> secondword;
144 }
145 }
146 return 1;
147 }
148 else
149 {
150 Cerr << word << " is not a keyword understood by " << que_suis_je() <<
151 " in lire_motcle_non_standard"<< finl;
153 }
154 return -1;
155}
156
158{
159 const int nb_boundaries=2*dimension;
160 F_old_.resize(nb_particles_tot_,nb_particles_tot_+nb_boundaries);
161 F_now_.resize(nb_particles_tot_,nb_particles_tot_+nb_boundaries);
162 e_eff_.resize(nb_particles_tot_,nb_particles_tot_+nb_boundaries);
163 Cerr << "WARNING: Collision_Model_FT_base::reset of F_old_, F_now_, "
164 "lagrangian_contact_forces_ and e_eff_." << finl;
165}
166
168{
169 Nom readword;
170 const int format_xyz = EcritureLectureSpecial::is_lecture_special();
171
172 is >> readword;
173 if (readword != que_suis_je())
174 {
175 Cerr << "Error in Collision_Model_FT_base::reprendre\n";
176 Cerr << "We was expecting " << que_suis_je();
177 Cerr << "\n We found " << readword << finl;
179 }
180 is >> nb_particles_tot_;
183 if (format_xyz)
184 {
185 for (int i=0; i<F_old_.dimension(0); i++)
186 for (int j=0; j<F_old_.dimension(1); j++)
187 is>>F_old_(i,j);
188 for (int i=0; i<e_eff_.dimension(0); i++)
189 for (int j=0; j<e_eff_.dimension(1); j++)
190 is>>e_eff_(i,j);
191 }
192 else
193 {
194 is>>F_old_;
195 is>>e_eff_;
196 }
197 return 1;
198}
199
201{
202 int special, afaire;
203 const int format_xyz = EcritureLectureSpecial::is_ecriture_special(special, afaire);
204 int bytes = 0;
205 if (format_xyz)
206 {
208 {
209 os << Nom(que_suis_je()) << finl;
210 os << nb_particles_tot_ << finl;
211 for (int i=0; i<F_old_.dimension(0); i++)
212 for (int j=0; j<F_old_.dimension(1); j++)
213 os<<F_old_(i,j);
214 for (int i=0; i<e_eff_.dimension(0); i++)
215 for (int j=0; j<e_eff_.dimension(1); j++)
216 os<<e_eff_(i,j);
217 }
218 return 0;
219 }
220 else
221 {
222 os << que_suis_je() << finl;
223 os << nb_particles_tot_ << finl;
224 os << F_old_;
225 bytes += 8 * F_old_.size_array();
226 os << e_eff_;
227 bytes += 8 * e_eff_.size_array();
228 return bytes;
229 }
230}
231
233 const int nb_particles_tot,
234 const Navier_Stokes_FT_Disc& ns,
235 const Transport_Interfaces_FT_Disc& eq_transport,
236 const Schema_Comm& schema_comm_FT)
237{
238 set_geometric_parameters(domain_vdf);
239 set_nb_particles_tot(nb_particles_tot);
240 set_nb_real_particles(nb_particles_tot);
243 const Fluide_Diphasique& two_phase_elem=ns.fluide_diphasique();
244 const int id_solid_phase=1-two_phase_elem.get_id_fluid_phase();
245 const Solid_Particle_base& solid_particle=ref_cast(Solid_Particle_base,
246 two_phase_elem.fluide_phase(id_solid_phase));
247 const double& diameter=solid_particle.get_equivalent_diameter();
248 set_activation_distance(diameter);
250 associate_transport_equation(eq_transport);
251
252 if (is_LC_activated())
253 set_LC_zones(domain_vdf,schema_comm_FT);
254
255 set_spring_properties(solid_particle);
256
257 if ((F_old_.dimension(0)!=nb_particles_tot) ||
258 (F_now_.dimension(0)!=nb_particles_tot) )
259 reset();
260
261 return 1;
262}
263
270
272{
274 {
275 const double mass_sphere = solid_particle.get_mass();
276 const double e_dry = solid_particle.get_e_dry();
277 const double mass_eff_part_part = mass_sphere/2;
278 const double mass_eff_wall_part = mass_sphere;
279
282
284 {
285 damper_breugem_part_part_ = compute_damper_breugem(mass_eff_part_part,e_dry);
286 damper_breugem_wall_part_ = compute_damper_breugem(mass_eff_wall_part,e_dry);
287 }
288 }
289}
290
292{
293 const Transport_Interfaces_FT_Disc& eq = ref_cast(Transport_Interfaces_FT_Disc,equation);
294 refequation_transport_ = eq;
295}
296
298{
299 DoubleVect offset_values(2*dimension);
300
302 {
303 case 0:
304 offset_values=0;
305 break;
306 case 1:
307 if (activation_distance_>0) offset_values=activation_distance_;
308 break;
309 default:
310 Cerr << "Collision_Model_FT_base::compute_fictive_wall_coordinates error" <<finl;
312 break;
313 }
314
315 // an offset is computed for the walls to activate the collision process before the impact
316 fictive_wall_coordinates_(0) = origin_(0) - radius + offset_values(0);
317 fictive_wall_coordinates_(1) = origin_(1) - radius + offset_values(1);
318 fictive_wall_coordinates_(2) = origin_(2) - radius + offset_values(2);
319 fictive_wall_coordinates_(3) = origin_(0) + domain_dimensions_(0) + radius - offset_values(3);
320 fictive_wall_coordinates_(4) = origin_(1) + domain_dimensions_(1) + radius - offset_values(4);
321 fictive_wall_coordinates_(5) = origin_(2) + domain_dimensions_(2) + radius - offset_values(5);
322
323 Cerr << "fictive_wall_coordinates\n" << fictive_wall_coordinates_ << finl;
324}
325
326/*! @brief Recover the geometric parameters of the domain:
327 * number of nodes in each direction
328 * origin of the domain
329 * dimensions of the domain
330 */
332{
333 const Domaine& domain = domaine_vdf.domaine();
334 const DoubleTab BB=domain.getBoundingBox();
335 const Bords& bords=domain.faces_bord();
336 DoubleVect NiNj(dimension); // NiNj=(NyNz NxNz NxNy )
338
339 // 1. Number of nodes per direction
340 NiNj=0;
341 for (int i=0; i<bords.nb_bords(); i++)
342 {
343 int nb_boundary_faces = Process::check_int_overflow(mp_sum(ref_cast(Frontiere,bords(i)).nb_faces()));
344 int nb_boundary_faces_local=ref_cast(Frontiere,bords(i)).nb_faces();
345 if (nb_boundary_faces_local>0)
346 {
347 int face1=ref_cast(Frontiere,bords(i)).num_premiere_face();
348 int orientation_face1=domaine_vdf.orientation(face1);
349 NiNj(orientation_face1)=nb_boundary_faces;
350 }
351 }
352 long long NxNy= static_cast<int>(mp_max(NiNj(2))) ;
353 long long NxNz= static_cast<int>(mp_max(NiNj(1)));
354 long long NyNz= static_cast<int>(mp_max(NiNj(0)));
355
356 int Nx,Ny,Nz;
357
358 Ny= NxNz>0 ? static_cast<int>(sqrt(NxNy*NyNz/NxNz)) : 0; // nb elem in the y-direction
359 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
360 Nx= Ny>0 ? static_cast<int>(NxNy/Ny) : 0; // nb elem in the x-direction
361
362 nb_nodes_(0)=Nx++; // nb nodes in the x-direction
363 nb_nodes_(1)=Ny++; // nb nodes in the y-direction
364 nb_nodes_(2)=Nz++; // nb nodes in the z-direction
365
366 // 2. Origin and Domain_dimensions
367 DoubleVect Origin(dimension);
368 DoubleVect Domain_dimensions(dimension);
369 Origin=0.;
370 Domain_dimensions=0.;
371
372 for (int j=0; j<dimension; j++)
373 {
374 double min_ = mp_min(BB(j,0));
375 double max_ = mp_max(BB(j,1));
376
377 Origin(j)=min_;
378 Domain_dimensions(j)=max_-min_;
379 }
380
381 set_origin(Origin);
382 set_domain_dimensions(Domain_dimensions);
383
384 Cerr << "Origin " << Origin << finl;
385 Cerr << "Domain length" << Domain_dimensions << finl;
386 Cerr << "Nx Ny Nz " << nb_nodes_ << finl;
387}
388
389/*! @brief Check if two particles have the same ID
390 * Very important function to stop computation if
391 * two particles coalesce.
392 */
394{
395 int flag =0;
396 ArrOfInt copy_vector(vector);
397 const int size = copy_vector.size_array();
398 copy_vector.ordonne_array();
399 for (int i = 0; i < size-1; i++)
400 {
401 if (copy_vector(i)==copy_vector(i+1))
402 {
403 flag = 1;
404 Cerr << copy_vector(i) << " is duplicate !!" << finl ;
405 }
406 }
407 return flag;
408}
409
410
411/* @brief we send the list of real particles to proc from lower zones
412 */
413ArrOfInt send_receive_list_id_particles(ArrOfInt& list_id_real_particles_to_send,
414 const ArrOfInt& list_lower_zone,
415 const Schema_Comm& schema_comm)
416{
417 ArrOfInt list_id_particle_recv;
418 list_id_particle_recv.resize_array(0);
419 //int nb_elem_recv=0;
420 const int nb_real_particles_to_send=list_id_real_particles_to_send.size_array();
421
422 schema_comm.begin_comm();
423
424 for (int ind_pe_dest=0; ind_pe_dest<list_lower_zone.size_array(); ind_pe_dest++)
425 {
426 int PE_dest=list_lower_zone(ind_pe_dest);
427 for(int ind_particle=0; ind_particle<nb_real_particles_to_send; ind_particle++)
428 {
429 const int id_particle=list_id_real_particles_to_send(ind_particle);
430 assert(PE_dest!=Process::me());
431 schema_comm.send_buffer(PE_dest) << id_particle;
432 }
433 }
434
435 schema_comm.echange_taille_et_messages();
436
437 const ArrOfInt& recv_pe_list = schema_comm.get_recv_pe_list();
438 const int nb_recv_pe = recv_pe_list.size_array();
439 for (int i=0; i<nb_recv_pe; i++)
440 {
441 const int pe_source = recv_pe_list[i];
442 Entree& buffer = schema_comm.recv_buffer(pe_source);
443 while(1)
444 {
445 int id_particle_recv=-1;
446 buffer >> id_particle_recv;
447 if (buffer.eof())
448 break;
449 if (id_particle_recv<0)
451 //nb_elem_recv++;
452 list_id_particle_recv.append_array(id_particle_recv);
453 }
454 }
455 schema_comm.end_comm();
456
457 return list_id_particle_recv;
458}
459
460
462 eq_ns,const Transport_Interfaces_FT_Disc& eq_transport)
463{
464 ArrOfInt list_particles_to_check_LC;
465 const ArrOfInt& gravity_center_elem=eq_transport.get_gravity_center_elem();
466 const Domaine_VF& domain_vf=ref_cast(Domaine_VF,eq_ns.domaine_dis());
467 const int& nb_elem=domain_vf.nb_elem();
468 const Maillage_FT_Disc& mesh=eq_transport.maillage_interface();
469 const Schema_Comm& schema_comm=mesh.get_schema_comm_FT();
470 const DoubleTab& particles_velocity=eq_transport.get_particles_velocity();
471 const DoubleTab& particles_position=eq_transport.get_particles_position();
472 const Fluide_Diphasique& two_phase_elem=eq_ns.fluide_diphasique();
473 const int id_solid=1-two_phase_elem.get_id_fluid_phase();
474 const auto& solid_particle=ref_cast(Solid_Particle_base,two_phase_elem.fluide_phase(id_solid));
475 const double& radius=solid_particle.get_equivalent_radius();
476 const Schema_Temps_base& time_scheme=eq_ns.schema_temps();
477 const double& time_step=time_scheme.pas_de_temps();
478
479 Cerr << "Update of Verlet tables - " ;
480 // Step 1 : update of Linked Cells (for more info on the method, see X. Fang et al.,
481 // J. Sound Vib., 2007).
482 // Here, each linked cell match a CPU domain. We seed the id of real particles to LC
483 // from lower zones (to receive LC from upper zones)
485 {
487 list_real_particles_.resize_array(0);
488 for (int particle=0; particle<nb_particles_tot_; particle++)
489 {
490 if (gravity_center_elem(particle)>-1 && gravity_center_elem(particle)<nb_elem)
491 {
492 list_real_particles_.append_array(particle);
494 }
495 }
497
498 //Process::barrier(); // we wait that all procs have updated their list to do the exchange
499 ArrOfInt list_virtual_particles;
500 const ArrOfInt& list_lower_zone=get_list_lower_zone();
501 list_virtual_particles=send_receive_list_id_particles(list_real_particles_,
502 list_lower_zone,
503 schema_comm);
504 if (nb_real_particles_>0)
505 {
506 Cerr << "list_real_particles_ " << list_real_particles_<< finl;
507 Cerr << "list_virtual_particles " << list_virtual_particles<< finl;
508 list_particles_to_check_LC.resize(list_real_particles_.size_array()+
509 list_virtual_particles.size_array());
510 for (int k=0; k<list_real_particles_.size_array()
511 +list_virtual_particles.size_array(); k++)
512 {
513 if (k<list_real_particles_.size_array()) list_particles_to_check_LC(k)=
515 else list_particles_to_check_LC(k)=
516 list_virtual_particles(k-list_real_particles_.size_array());
517 }
518 Cerr << "list_particles_to_check_LC " << list_particles_to_check_LC<< finl; // do not sort the list
519 }
520 }
521 // ETAPE B : update of Verlet tables
522 // we compute the distance between particles and we save the pairs that are within
523 // the distance detection_thickness_Verlet_. I usually define it as 30% of the particle
524 // diameter in the data file.
525 // For Verlet table without LC, we test all particle pairs
526 // For Verlet method with LC, for all real particles, we test all particles
527 // pairs from the upper zone (proc domain + upper procs domain)
528 double max_vi_glob=0;
529 double max_vi=0.;
530 if (nb_real_particles_>0)
531 {
534
535 compute_Verlet_tables(particles_position,
536 particles_velocity,
537 max_vi,
538 radius,
539 list_particles_to_check_LC);
540 }
541 max_vi_glob=mp_max(max_vi); // with the linked cell method, we compute the max.
542 // With only Verlet method,
543 // there is no need to, but max_vi=mp_max(max_vi) for each proc.
544 // Computing the next Verlet table update time step based on the maximum velocity
545 // of a particle in the domain
546 int deltat_compute_min = (max_vi_glob>0) ?
547 static_cast<int>(floor((detection_thickness_Verlet_/(2*max_vi_glob))/
548 time_step)) :
550
551 nb_dt_compute_Verlet_=std::min(deltat_compute_min,nb_dt_max_Verlet_);
552 Cerr << "Next update in " <<nb_dt_compute_Verlet_ << " time steps." << finl;
554 // Cerr to check if Verlet tables are correctly filled
555 if (nb_particles_tot_<20)
556 {
557 for (int ind_part_i=0; ind_part_i <nb_real_particles_; ind_part_i++)
558 {
559 Cerr << "Verlet_tables_["<<ind_part_i<<"].size() " << Verlet_tables_[ind_part_i].size() << " -- ";
560 for (int ind_part_j=0; ind_part_j<Verlet_tables_[ind_part_i].size(); ind_part_j++)
561 Cerr << " " << Verlet_tables_[ind_part_i][ind_part_j];
562 Cerr << finl;
563 }
564 }
565}
566
567int Collision_Model_FT_base::get_last_id(const ArrOfInt& list_particles_to_check_LC)
568{
570 Process::exit("Collision_Model_FT_base::get_last_id Should not be in here!");
572 return nb_particles_tot_;
574 return(list_particles_to_check_LC.size_array());
575 return 0;
576}
577
578
579int Collision_Model_FT_base::get_id(const ArrOfInt& list_particle, const int ind_id_particle)
580{
582 Process::exit("Collision_Model_FT_base::get_id Should not be in here!");
584 return(ind_id_particle);
586 return(list_particle(ind_id_particle));
587 else
588 Process::exit("Collision_Model_FT_base::get_id unkwnown detection_method_!");
589 return 0;
590}
591
592int Collision_Model_FT_base::get_particle_j(const int ind_particle_i, const int ind_particle_j)
593{
595 return(ind_particle_j);
598 return (Verlet_tables_[ind_particle_i][ind_particle_j]);
599 return 0;
600}
601
602int Collision_Model_FT_base::get_nb_particles_j(const int ind_particle_i) const
603{
605 return (nb_particles_tot_+2*dimension);
608 return (Verlet_tables_[ind_particle_i].size());
609 return 0;
610}
611
612int Collision_Model_FT_base::get_particle_i(const int ind_particle_i)
613{
615 list_real_particles_(ind_particle_i) : ind_particle_i);
616}
617
618int Collision_Model_FT_base::get_ind_start_particles_j(const int ind_particle_i) const
619{
621 (ind_particle_i+1) : 0);
622}
623
624
625void Collision_Model_FT_base::compute_Verlet_tables(const DoubleTab& particles_position,
626 const DoubleTab& particles_velocity,
627 double& max_vi,
628 const double& radius,
629 const ArrOfInt& list_particles_to_check_LC)
630{
631 int last_id = get_last_id(list_particles_to_check_LC);
632 for (int ind_id_particle_i=0; ind_id_particle_i< nb_real_particles_; ind_id_particle_i++)
633 {
634 int id_particle_i=get_id(list_particles_to_check_LC,ind_id_particle_i);
635 const double vi=fabs(sqrt(
636 pow(particles_velocity(id_particle_i,0),2) +
637 pow(particles_velocity(id_particle_i,1),2) +
638 pow(particles_velocity(id_particle_i,2),2)));
639 if (vi>max_vi)
640 max_vi=vi;
641 // particle-particle distance
642 for (int ind_id_particle_j=ind_id_particle_i+1; ind_id_particle_j< last_id; ind_id_particle_j++)
643 {
644 int id_particle_j= get_id(list_particles_to_check_LC, ind_id_particle_j);
645 double dij=sqrt(
646 pow(particles_position(id_particle_j,0)-particles_position(id_particle_i,0),2) +
647 pow(particles_position(id_particle_j,1)-particles_position(id_particle_i,1),2) +
648 pow(particles_position(id_particle_j,2)-particles_position(id_particle_i,2),2));
649
650 if ((dij-2*radius)<=detection_thickness_Verlet_)
651 Verlet_tables_[ind_id_particle_i].add(id_particle_j);
652
653 }
654
655 // wall-particle distance
656 for (int ind_wall=0; ind_wall<2*dimension; ind_wall++)
657 {
658 const int ori = ind_wall < dimension ? ind_wall : ind_wall - dimension;
659 const double dij=fabs(fictive_wall_coordinates_(ind_wall)-
660 particles_position(id_particle_i,ori));
661
662 if ((dij-2*radius)<=detection_thickness_Verlet_)
663 Verlet_tables_[ind_id_particle_i].add(nb_particles_tot_+ind_wall);
664 }
665 }
666}
667
668
670 DoubleTab& dU,
671 const int& particle,
672 const int& neighbor,
673 const DoubleTab& particles_position,
674 const DoubleTab& particles_velocity,
675 const bool is_particle_particle_collision)
676{
677 if (is_particle_particle_collision)
678 {
679 for (int d = 0; d < dimension; d++)
680 {
681 dX(d) = particles_position(particle, d) - particles_position(neighbor, d);
682 dU(d) = particles_velocity(particle, d) - particles_velocity(neighbor, d);
683 }
684 }
685 else
686 {
687 int ind_wall = neighbor - nb_particles_tot_;
688 int ori = ind_wall < dimension ? ind_wall : ind_wall - dimension;
689 dX(ori) = particles_position(particle, ori) - fictive_wall_coordinates_(ind_wall);
690 for (int d = 0; d < dimension; d++)
691 dU(d) = particles_velocity(particle, d);
692 }
693}
694
696 const double& next_dist_int,
697 const DoubleTab& norm,
698 const DoubleTab& dUn,
699 const int& particle_i,
700 const int& particle_j,
701 const int& is_compression_step,
702 const double& is_collision_part_part)
703{
704 DoubleTab force_contact(dimension);
705
706 if (collision_model_==Collision_model::HYBRID_ESI) // see Hamidi et al., IJMF, 2023.
707 {
708 const double e_eff_particle = is_compression_step ? 1 : e_eff_(particle_i, particle_j);
709 const double stiffness = is_collision_part_part ? stiffness_breugem_part_part_:
711 for (int d = 0; d < dimension; d++)
712 force_contact(d)= -pow(e_eff_particle,2) * stiffness * next_dist_int * norm(d);
713 }
714 else if (collision_model_==Collision_model::BREUGEM) // See. W-P. Breugem, 2010.
715 {
716 const double stiffness = is_collision_part_part ? stiffness_breugem_part_part_:
718 const double damper = is_collision_part_part ? damper_breugem_part_part_:
720 for (int d = 0; d < dimension; d++)
721 force_contact(d)= -stiffness*next_dist_int*norm(d) -damper*dUn(d);
722 }
723 else
724 Process::exit("Collision_Model_FT_base::compute_contact_force unknown collision_model_");
725
726 return force_contact;
727}
728
730 const DoubleTab& volumic_phase_indicator_function,
731 const Domaine_VF& domain_vf,
732 const IntTab& particles_eulerian_id_number,
733 DoubleTab& contact_force_source_term)
734{
735 Process::exit("Collision_Model_FT_base::discretize_contact_forces_eulerian_field "
736 "not coded for particles of arbitrary shape");
737}
738
740{
742 return false;
743 return true;
744}
745
747{
749 return true;
750 return false;
751}
752
753void Collision_Model_FT_base::set_LC_zones(const Domaine_VF& domain_vf, const Schema_Comm& schema_com)
754{
755 int nsup=0;
756 int ninf=0;
757
758 int nb_joints=domain_vf.nb_joints();
759
760 double x0 = domain_vf.xp(0,0);
761 double y0 = domain_vf.xp(0,1);
762 double z0 = domain_vf.xp(0,2);
763 double epsilon=1e-10;
764 const int nb_elems=domain_vf.nb_elem();
765 const int nb_elems_tot=domain_vf.nb_elem_tot();
766
767 Cerr << "number or reals elements " << nb_elems << finl;
768 Cerr << "total number of elements " << nb_elems_tot << finl;
769 Cerr << "(x0 y0 z0) = (" << x0 << " " << y0 << " " << z0 << ")" << finl;
770 Cerr << "joints number " << nb_joints << finl;
771
772 // Firstly, every proc send coordinates of its first elem to other procs
773 DoubleTabFT list_coord_recv(0,dimension);
774 IntTabFT list_pe_recv(0);
775 Cerr << "list_coord_recv.dimensions " << list_coord_recv.dimension(0) << " "
776 << list_coord_recv.dimension(1) << finl;
777 int nb_elem_recv=0;
778
779 schema_com.begin_comm();
780
781 for (int ind_pe_dest=0; ind_pe_dest<nb_joints; ind_pe_dest++)
782 {
783 const Joint& joint_temp = domain_vf.joint(ind_pe_dest);
784 const int pe_dest = joint_temp.PEvoisin();
785 assert(pe_dest!=Process::me());
786 schema_com.send_buffer(pe_dest) << x0 << y0 << z0;
787 }
788
789 schema_com.echange_taille_et_messages();
790
791 const ArrOfInt& recv_pe_list = schema_com.get_recv_pe_list();
792 const int nb_recv_pe = recv_pe_list.size_array();
793 for (int i=0; i<nb_recv_pe; i++)
794 {
795 const int pe_source = recv_pe_list[i];
796 Entree& buffer = schema_com.recv_buffer(pe_source);
797 while(1)
798 {
799 double x0_rcv=-1, y0_rcv=-1, z0_rcv=-1;
800 buffer >> x0_rcv >> y0_rcv >> z0_rcv;
801 if (buffer.eof())
802 break;
803 nb_elem_recv++;
804 list_coord_recv.append_line(x0_rcv,y0_rcv,z0_rcv);
805 list_pe_recv.append_line(pe_source);
806 }
807 }
808
809 schema_com.end_comm();
810
811 list_coord_recv.resize(nb_elem_recv,dimension);
812 list_pe_recv.resize(nb_elem_recv);
813
814 if (nb_joints != nb_elem_recv) Process::exit("EB : Collision_Model_FT_base::"
815 "set_LC_zones -- erreur identification du 1er element"
816 " des procs de la zone de joint.");
817 for(int ind_pe=0; ind_pe<nb_elem_recv; ind_pe++)
818 {
819 const int pe_voisin = list_pe_recv(ind_pe);
820 double x0_joint = list_coord_recv(ind_pe,0);
821 double y0_joint = list_coord_recv(ind_pe,1);
822 double z0_joint = list_coord_recv(ind_pe,2);
823
824 if ( y0_joint>y0 || (fabs(y0_joint-y0)<epsilon && x0_joint>x0) ||
825 ( fabs(x0_joint-x0) < epsilon && fabs(y0_joint-y0)<epsilon && (z0_joint>z0)) )
826 list_upper_zone_.append_array(pe_voisin), nsup++;
827 if ( y0_joint<=y0 && (fabs(y0_joint-y0)>=epsilon || x0_joint<=x0)
828 && ( fabs(x0_joint-x0) >= epsilon || fabs(y0_joint-y0)>=epsilon
829 || (z0_joint<=z0)) )
830 list_lower_zone_.append_array(pe_voisin), ninf++;
831
832 }
833
834 list_upper_zone_.resize_array(nsup);
835 list_lower_zone_.resize_array(ninf);
836
837 Cerr << "list_upper_zone_ " << list_upper_zone_ << finl;
838 Cerr << "list_lower_zone_ " << list_lower_zone_ << finl;
839 Cerr << "max number of upper zone = " << mp_max(nsup) << finl;
840 Cerr << "max number of lower zone = " << mp_max(ninf) << finl;
841}
842
843void Collision_Model_FT_base::add_collision(const int part_i, const int part_j, const bool is_part_part_collision)
844{
845 const double contrib=is_part_part_collision? 1 : .2; // for wall_particle_collision we add .2 (for post-processing)
846 if (part_i<nb_particles_tot_)
847 particles_collision_number_(part_i)+=contrib;
848 if (part_j<nb_particles_tot_)
849 particles_collision_number_(part_i)+=contrib;
850}
851
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