@@ -374,5 +374,119 @@ namespace rascal {
374
374
} // manager
375
375
return neg_stress_name;
376
376
}
377
+
378
+
379
+ /* *
380
+ * Compute the atomic gradients of a structure w.r.t atomic cell paramaters
381
+ * using a sparse GPR model. Only SOAP-GAP model is implemented at the moment
382
+ * (see
383
+ * @ref SparseKernelImpl<internal::SparseKernelType::GAP>::compute_derivative)
384
+ *
385
+ * The point of this function is to provide a faster prediction routine
386
+ * compared to computing the kernel elements and then multiplying them with
387
+ * the weights of the model.
388
+ *
389
+ * The gradients are attached to the input manager in a Property of
390
+ * Order 1 with the name
391
+ * '"kernel: "+kernel_type+" ; "+representation_grad_name+" negative stress;
392
+ * weight_hash:"+weight_hash' gradients [2*n_managers, 3]
393
+ *
394
+ * @tparam StructureManagers should be an iterable over shared pointer
395
+ * of structure managers like ManagerCollection
396
+ * @param sparse_points a SparsePoints* class
397
+ * @param managers a ManagerCollection or similar collection of
398
+ * structure managers
399
+ * @param weights regression weights of the sparse GPR model
400
+ * @return name used to register the gradients in the managers
401
+ */
402
+ template <class Calculator , class StructureManagers , class SparsePoints >
403
+ std::string compute_sparse_kernel_local_neg_stress (const Calculator & calculator,
404
+ SparseKernel & kernel,
405
+ StructureManagers & managers,
406
+ SparsePoints & sparse_points,
407
+ math::Vector_t & weights) {
408
+ using Manager_t = typename StructureManagers::Manager_t;
409
+ using Property_t = typename Calculator::template Property_t<Manager_t>;
410
+ using PropertyGradient_t =
411
+ typename Calculator::template PropertyGradient_t<Manager_t>;
412
+ auto && representation_name{calculator.get_name ()};
413
+ const auto representation_grad_name{calculator.get_gradient_name ()};
414
+ size_t n_centers{0 };
415
+ // find the total number of gradients
416
+ for (const auto & manager : managers) {
417
+ n_centers += manager->size ();
418
+ }
419
+
420
+ // Voigt order is xx, yy, zz, yz, xz, xy. To compute xx, yy, zz
421
+ // and yz, xz, xy in one loop over the three spatial dimensions
422
+ // dK/dr_{x,y,z}, we fill the off-diagonals yz, xz, xy by computing
423
+ // xz, yx, zy exploiting the symmetry of the stress tensor
424
+ // thus yx=xy and zx=xz
425
+ // array accessed by voigt_idx and returns spatial_dim_idx
426
+ const std::array<std::array<int , 2 >, ThreeD> voigt_id_to_spatial_dim = {
427
+ { // voigt_idx, spatial_dim_idx
428
+ {{4 , 2 }}, // xz, z
429
+ {{5 , 0 }}, // xy, x
430
+ {{3 , 1 }}}}; // yz, y
431
+
432
+ internal::Hash<math::Vector_t, double > hasher{};
433
+ auto kernel_type_str = kernel.parameters .at (" name" ).get <std::string>();
434
+ std::string weight_hash = std::to_string (hasher (weights));
435
+ std::string pair_grad_atom_i_r_j_name =
436
+ std::string (" kernel: " ) + kernel_type_str + std::string (" ; " ) +
437
+ representation_grad_name +
438
+ std::string (" partial gradients; weight_hash:" ) + weight_hash;
439
+ std::string neg_stress_name =
440
+ std::string (" kernel: " ) + kernel_type_str + std::string (" ; " ) +
441
+ representation_grad_name +
442
+ std::string (" negative stress; weight_hash:" ) + weight_hash;
443
+
444
+ for (const auto & manager : managers) {
445
+ if (kernel_type_str == " GAP" ) {
446
+ const auto zeta = kernel.parameters .at (" zeta" ).get <size_t >();
447
+
448
+ compute_partial_gradients_gap<Property_t, PropertyGradient_t>(
449
+ manager, sparse_points, weights, zeta, representation_name,
450
+ representation_grad_name, pair_grad_atom_i_r_j_name);
451
+ }
452
+
453
+ auto && neg_stress{
454
+ *manager->template get_property <Property<double , 0 , Manager_t, 6 >>(
455
+ neg_stress_name, true , true , true )};
456
+ if (neg_stress.is_updated ()) {
457
+ continue ;
458
+ }
459
+
460
+ neg_stress.resize ();
461
+ neg_stress.setZero ();
462
+
463
+ auto && pair_grad_atom_i_r_j{*manager->template get_property <
464
+ Property<double , 2 , Manager_t, 1 , ThreeD>>(pair_grad_atom_i_r_j_name,
465
+ true )};
466
+ for (auto center : manager) {
467
+ Eigen::Vector3d r_i = center.get_position ();
468
+ // accumulate partial gradients onto gradients
469
+ for (auto neigh : center.pairs_with_self_pair ()) {
470
+ Eigen::Vector3d r_ji = r_i - neigh.get_position ();
471
+ for (int i_der{0 }; i_der < ThreeD; i_der++) {
472
+ const auto & voigt = voigt_id_to_spatial_dim[i_der];
473
+ neg_stress (i_der) +=
474
+ r_ji (i_der) * pair_grad_atom_i_r_j[neigh](i_der);
475
+ neg_stress (voigt[0 ]) +=
476
+ r_ji (voigt[1 ]) * pair_grad_atom_i_r_j[neigh](i_der);
477
+ }
478
+ }
479
+ }
480
+ auto manager_root = extract_underlying_manager<0 >(manager);
481
+ json structure_copy = manager_root->get_atomic_structure ();
482
+ auto atomic_structure =
483
+ structure_copy.template get <AtomicStructure<ThreeD>>();
484
+ neg_stress[0 ] /= atomic_structure.get_volume ();
485
+ neg_stress.set_updated_status (true );
486
+ } // manager
487
+ return neg_stress_name;
488
+ }
489
+
490
+
377
491
} // namespace rascal
378
492
#endif // SRC_RASCAL_MODELS_SPARSE_KERNEL_PREDICT_HH_
0 commit comments