Skip to main content

Rocky Solver SDK 2024 R2

api_device_contacts

Last update: 17.07.2025
1#pragma once
2
3#include <rocky20/api/rocky_model_api.hpp>
4#include <rocky20/device/device_forces.hpp>
5#include <rocky20/device/device_contact.hpp>
6
7namespace
8{
9
10template <typename ForcePipelineFunctions>
11__host__ __device__ void api_process_frictional_contact_data(
12 IRockyContact& contact_api,
13 IRockyContactOutputData& contact_output,
14 const ForcePipelineFunctions& functions,
15 void* udf_data)
16{
17 auto rocky_contact = contact_api._impl;
18
19 // Intermediate Data
20 IRockyContactIntermediateData contact_idata {};
21 cuda_contact_intermediate_data& idata = contact_idata._idata;
22
23 // Output Data
24 contact_output_data& output = contact_output._output;
25
26 device::get_frictional_contact_general_parameters(
27 *rocky_contact, output, idata, contact_api.get_current_time());
28
29 // Custom (or standard) function calculating contact normal force
30 functions.template run<EForcePipelineFunctions::fpfComputeNormalForce>(
31 contact_api, contact_idata, contact_output, udf_data);
32
33 // Custom (or standard) function calculating contact tangential force
34 functions.template run<EForcePipelineFunctions::fpfComputeTangentialForce>(
35 contact_api, contact_idata, contact_output, udf_data);
36
37 if (rocky_contact->get_tangential_force_model() == tfmCustom)
38 device::calculate_mu_and_slip(*rocky_contact, contact_output, contact_idata);
39
40 // Custom (or standard) function calculating contact rolling resistance
41 functions.template run<EForcePipelineFunctions::fpfComputeRollingResistance>(
42 contact_api, contact_idata, contact_output, udf_data);
43 if (!contact_output._is_rr_power_set)
44 device::calculate_standard_rr_power(*rocky_contact, contact_idata, contact_output);
45
46 // Custom (or standard) function calculating contact impact energies
47
48 if (rocky_contact->model->gen->flags.needs_impact_energy())
49 {
50 functions.template run<EForcePipelineFunctions::fpfComputeImpactEnergy>(
51 contact_api, contact_idata, contact_output, udf_data);
52 }
53
54 device::calculate_standard_shear_energy(contact_output, contact_api);
55
56 device::get_total_frictional_forces_and_moments(*rocky_contact, output, idata);
57
58 /* updating stored values */
59 const int contact_index = rocky_contact->contact_index;
60 rocky20::ContactScalars& scalars = rocky_contact->get_scalars();
61
62 if (rocky_contact->get_normal_force_model() != nfmLinearHysteresis)
63 scalars.get_normal_force(contact_index) = output.normal_force;
64
65 if (scalars.has_tangential_force_enabled()
66 && (rocky_contact->get_tangential_force_model() == tfmCustom
67 || rocky_contact->get_tangential_force_model() == tfmCoulombLimitTangential))
68 scalars.get_tangential_forces()[contact_index] = output.tangential_force;
69
70 if (scalars.has_tangential_sliding_enabled()
71 && rocky_contact->get_tangential_force_model() == tfmCustom)
72 scalars.get_is_sliding_scalars()[contact_index] = contact_output._sliding;
73
74 if (scalars.has_sliding_distance())
75 scalars.get_sliding_distance(contact_index) = output.sliding_distance;
76 if (scalars.has_normal_relative_velocity())
77 scalars.get_normal_relative_velocity(contact_index) = output.normal_velocity;
78 if (scalars.has_tangential_relative_velocity())
79 scalars.get_tangential_relative_velocity(contact_index) = output.tangential_velocity;
80
81 if (rocky_contact->model->gen->flags.needs_energy_dissipation())
82 device::compute_frictional_dissipation_energy(
83 *rocky_contact, output, idata, output.rr_power);
84}
85
86
87template <typename Callable>
88__host__ __device__ void api_process_adhesive_contact_data(
89 IRockyContact& contact_api, IRockyAdhesionOutputData& output_data,
90 Callable process_contact_ptr, void *udf_data,
91 cu_real* normal_adhesion_forces, cu_real3* tangential_adhesion_forces
92)
93{
94 cuda_contact_intermediate_data idata{};
95 auto rocky_contact = contact_api._impl;
96
97 device::get_adhesive_contact_general_parameters(
98 *rocky_contact, output_data._output, idata, contact_api.get_current_time());
99
100 // Custom function calculating adhesive force
101 process_contact_ptr(contact_api, output_data, udf_data);
102 auto& output = output_data._output;
103
104 const auto scale = rocky_contact->get_scale();
105 output.adhesive_normal_force *= scale;
106 output.adhesive_tangential_force *= scale;
107
108 output.force = output.adhesive_normal_force * rocky_contact->get_normal_unit_vector()
109 + output.adhesive_tangential_force;
110
111 if (rocky_contact->model->gen->flags.needs_energy_dissipation())
112 device::compute_adhesive_dissipation_energy(*rocky_contact, output, idata);
113
114 if (normal_adhesion_forces)
115 normal_adhesion_forces[rocky_contact->contact_index] = output.adhesive_normal_force;
116 if (tangential_adhesion_forces)
117 tangential_adhesion_forces[rocky_contact->contact_index] = output.adhesive_tangential_force;
118
119 output.home_moment = cross(idata.home_arm, output.force);
120 if (rocky_contact->is_particle_contact)
121 output.near_moment = -cross(idata.near_arm, output.force);
122}
123
124} // namespace
125
126
127namespace device
128{
129
130template <class backend, typename Callable>
131__host__ __device__ void execute_contacts_function(
132 SDeviceModel *device_data, cu_real current_time,
133 unsigned int *contact_indexes, int total_number_contacts,
134 bool is_particle_contacts,
135 Callable process_contact_ptr, void *udf_data
136)
137{
138 IRockyDeviceModel device_model_api;
139 RockyContact rocky_contact(device_data, is_particle_contacts);
140 IRockyContact contact_api { &rocky_contact, current_time };
141 device_model_api._impl.model = device_data;
142 device_model_api._impl.current_time = current_time;
143
144 // Thread
145 int thread_start, thread_step, thread_stop;
146 backend::ThreadIteration(thread_start, thread_step, thread_stop, total_number_contacts);
147 for (int index = thread_start; index < thread_stop; index += thread_step)
148 {
149 unsigned int contact_index = contact_indexes[index];
150 rocky_contact.reset(contact_index);
151 const SContactState state = rocky_contact.get_state();
152 if (!state.disabled())
153 {
154 process_contact_ptr(device_model_api, contact_api, udf_data);
155 }
156 }
157}
158
159template <class backend, typename Callable>
160__host__ __device__ void execute_finished_contacts_function(
161 SDeviceModel* device_data, cu_real current_time,
162 int total_number_contacts,
163 bool is_particle_contacts,
164 Callable process_contact_ptr, void* udf_data
165)
166{
167 IRockyDeviceModel device_model_api;
168 RockyContact rocky_contact(device_data, is_particle_contacts);
169 IRockyContact contact_api { &rocky_contact, current_time };
170 device_model_api._impl.model = device_data;
171 device_model_api._impl.current_time = current_time;
172
173 // Thread
174 int thread_start, thread_step, thread_stop;
175 backend::ThreadIteration(thread_start, thread_step, thread_stop, total_number_contacts);
176 for (int index = thread_start; index < thread_stop; index += thread_step)
177 {
178 rocky_contact.reset(index);
179 if (rocky_contact.just_finished_adhesive() || rocky_contact.just_finished_frictional())
180 {
181 process_contact_ptr(device_model_api, contact_api, udf_data);
182 }
183 }
184}
185
186template <class backend, typename Callable>
187__host__ __device__ void execute_active_contacts_function(
188 SDeviceModel* device_data, cu_real current_time,
189 int total_number_contacts,
190 bool is_particle_contacts,
191 Callable process_contact_ptr, void* udf_data
192)
193{
194 IRockyDeviceModel device_model_api;
195 RockyContact rocky_contact(device_data, is_particle_contacts);
196 IRockyContact contact_api { &rocky_contact, current_time };
197 device_model_api._impl.model = device_data;
198 device_model_api._impl.current_time = current_time;
199
200 // Thread
201 int thread_start, thread_step, thread_stop;
202 backend::ThreadIteration(thread_start, thread_step, thread_stop, total_number_contacts);
203 for (int index = thread_start; index < thread_stop; index += thread_step)
204 {
205 rocky_contact.reset(index);
206 const SContactState state = rocky_contact.get_state();
207 if (state.is_frictional() || state.is_adhesive())
208 {
209 process_contact_ptr(device_model_api, contact_api, udf_data);
210 }
211 }
212}
213
214template <class backend, typename Callable>
215__host__ __device__ void execute_all_contacts_function(
216 SDeviceModel *device_data, cu_real current_time,
217 int total_number_contacts,
218 bool is_particle_contacts,
219 Callable process_contact_ptr, void *udf_data
220)
221{
222 IRockyDeviceModel device_model_api;
223 RockyContact rocky_contact(device_data, is_particle_contacts);
224 IRockyContact contact_api { &rocky_contact, current_time };
225 device_model_api._impl.model = device_data;
226 device_model_api._impl.current_time = current_time;
227 contact_api._impl = &rocky_contact;
228
229 // Thread
230 int thread_start, thread_step, thread_stop;
231 backend::ThreadIteration(thread_start, thread_step, thread_stop, total_number_contacts);
232 for (int contact_index = thread_start; contact_index < thread_stop; contact_index += thread_step)
233 {
234 //Process frictional contacts
235 rocky_contact.reset(contact_index);
236 const SContactState state = rocky_contact.get_state();
237 if (!state.disabled())
238 {
239 process_contact_ptr(device_model_api, contact_api, udf_data);
240 }
241 }
242}
243
244template <class backend, typename ForcePipelineFunctions>
245__host__ __device__ void api_compute_particle_contact_frictional_forces(
246 SDeviceModel* device_data,
247 cu_real current_time,
248 const ForcePipelineFunctions& functions,
249 void* udf_data)
250{
251 RockyContact rocky_contact(device_data, true);
252 IRockyContact contact_api { &rocky_contact, current_time };
253
254 // Thread
255 int thread_start, thread_step, thread_stop;
256 backend::ThreadIteration(thread_start, thread_step, thread_stop, device_data->n_contacts->particle_fr);
257 for (int index = thread_start; index < thread_stop; index += thread_step)
258 {
259 unsigned int contact_index = device_data->ind_cnt_p_fr[index];
260 rocky_contact.reset(contact_index);
261
262 if (!rocky_contact.get_state().disabled())
263 {
264 IRockyContactOutputData contact_output{};
265
266 api_process_frictional_contact_data(contact_api, contact_output, functions, udf_data);
267
268 update_frictional_particle_contact_forces_and_statistics<backend>(
269 rocky_contact, contact_output._output, current_time);
270 }
271 }
272}
273
274template <class backend, typename ForcePipelineFunctions>
275__host__ __device__ void api_compute_triangle_contact_frictional_forces(
276 SDeviceModel *device_data, cu_real current_time,
277 const ForcePipelineFunctions& functions, void *udf_data
278)
279{
280 RockyContact rocky_contact(device_data, false);
281 IRockyContact contact_api { &rocky_contact, current_time };
282
283 // Thread
284 int thread_start, thread_step, thread_stop;
285 backend::ThreadIteration(thread_start, thread_step, thread_stop, device_data->n_contacts->triangle_fr);
286 for (int index = thread_start; index < thread_stop; index += thread_step)
287 {
288 unsigned int contact_index = device_data->ind_cnt_t_fr[index];
289 rocky_contact.reset(contact_index);
290
291 if (!rocky_contact.get_state().disabled())
292 {
293 IRockyContactOutputData contact_output{};
294
295 api_process_frictional_contact_data(contact_api, contact_output, functions, udf_data);
296
297 update_frictional_triangle_contact_forces_and_statistics<backend>(
298 rocky_contact, contact_output._output, current_time);
299 }
300 }
301}
302
303template <class backend, typename Callable>
304__host__ __device__ void api_compute_particle_contact_adhesive_forces(
305 SDeviceModel* device_data, cu_real current_time, Callable process_contact_ptr, void* udf_data)
306{
307 RockyContact rocky_contact(device_data, true);
308 IRockyContact contact_api { &rocky_contact, current_time };
309
310 rocky20::ContactScalars* contact_scalars = device_data->current_particle_contact_scalars;
311 cu_real* normal_adhesion_forces = contact_scalars->has_normal_adhesion_force() ?
312 contact_scalars->get_normal_adhesion_forces() : nullptr;
313 cu_real3* tangential_adhesion_forces = contact_scalars->has_tangential_adhesion_force() ?
314 contact_scalars->get_tangential_adhesion_forces() : nullptr;
315
316 // Thread
317 int thread_start, thread_step, thread_stop;
318 backend::ThreadIteration(thread_start, thread_step, thread_stop, device_data->n_contacts->particle_ad);
319 for (int index = thread_start; index < thread_stop; index += thread_step)
320 {
321 unsigned int contact_index = device_data->ind_cnt_p_ad[index];
322 const SContactState state = contact_scalars->get_state(contact_index);
323
324 if (!state.disabled())
325 {
326 rocky_contact.reset(contact_index);
327 IRockyAdhesionOutputData adhesion_output{};
328
329 api_process_adhesive_contact_data(
330 contact_api, adhesion_output,
331 process_contact_ptr, udf_data,
332 normal_adhesion_forces, tangential_adhesion_forces
333 );
334
335 update_adhesive_particle_contact_forces_and_statistics<backend>(
336 rocky_contact, adhesion_output._output);
337 }
338 }
339}
340
341template <class backend, typename Callable>
342__host__ __device__ void api_compute_triangle_contact_adhesive_forces(
343 SDeviceModel* device_data, cu_real current_time, Callable process_contact_ptr, void* udf_data)
344{
345 RockyContact rocky_contact(device_data, false);
346 IRockyContact contact_api { &rocky_contact, current_time };
347
348 rocky20::ContactScalars* contact_scalars = device_data->current_triangle_contact_scalars;
349 cu_real* normal_adhesion_forces = contact_scalars->has_normal_adhesion_force() ?
350 contact_scalars->get_normal_adhesion_forces() : nullptr;
351 cu_real3* tangential_adhesion_forces = contact_scalars->has_tangential_adhesion_force() ?
352 contact_scalars->get_tangential_adhesion_forces() : nullptr;
353
354 // Thread
355 int thread_start, thread_step, thread_stop;
356 backend::ThreadIteration(thread_start, thread_step, thread_stop, device_data->n_contacts->triangle_ad);
357 for (int index = thread_start; index < thread_stop; index += thread_step)
358 {
359 unsigned int contact_index = device_data->ind_cnt_t_ad[index];
360 const SContactState state = contact_scalars->get_state(contact_index);
361
362 if (!state.disabled())
363 {
364 rocky_contact.reset(contact_index);
365 IRockyAdhesionOutputData adhesion_output{};
366
367 api_process_adhesive_contact_data(
368 contact_api, adhesion_output,
369 process_contact_ptr, udf_data,
370 normal_adhesion_forces, tangential_adhesion_forces
371 );
372
373 update_adhesive_triangle_contact_forces_and_statistics<backend>(
374 rocky_contact, adhesion_output._output);
375 }
376 }
377}
378
379template <class backend, typename Callable>
380__host__ __device__ void api_compute_boundaries_wear(
381 SDeviceModel* device_data,
382 const cu_real current_time,
383 Callable process_triangle_wear_f_ptr,
384 void* udf_data)
385{
386 RockyContact rocky_contact(device_data, false);
387
388 IRockyContact contact_api;
389 contact_api._impl = &rocky_contact;
390
391 int thread_start, thread_step, thread_stop;
392 backend::ThreadIteration(thread_start, thread_step, thread_stop, device_data->n_contacts->triangle_fr);
393 for (int index = thread_start; index < thread_stop; index += thread_step)
394 {
395 unsigned int contact_index = device_data->ind_cnt_t_fr[index];
396 rocky_contact.reset(contact_index);
397 const SContactState state = rocky_contact.get_state();
398
399 if (!state.disabled())
400 {
401 auto& boundary = rocky_contact.get_near_boundary();
402 if (boundary.wear_model == wmCustom)
403 {
404 double wear_volume;
405 process_triangle_wear_f_ptr(contact_api, wear_volume, udf_data);
406 accumulate_wear_volume<backend>(rocky_contact, wear_volume, current_time);
407 }
408 }
409 }
410}
411
412} // namespace device
Definition rocky_contact_output_data_api.hpp:303
Definition rocky_contact_intermediate_data_api.hpp:17
Definition rocky_contact_output_data_api.hpp:37
ROCKY_FUNCTIONS double get_normal_relative_velocity()
Definition rocky_contact_output_data_api.hpp:279
Definition rocky_contact_api.hpp:46
ROCKY_FUNCTIONS double get_current_time() const
Definition rocky_contact_api.hpp:609
Definition rocky_model_api.hpp:19

Connect with Ansys