Skip to content

Commit

Permalink
Add PhysicalModelCollection (RobotLocomotion#21424)
Browse files Browse the repository at this point in the history
  • Loading branch information
xuchenhan-tri authored May 16, 2024
1 parent a41fd39 commit 2a544cc
Show file tree
Hide file tree
Showing 5 changed files with 389 additions and 15 deletions.
28 changes: 14 additions & 14 deletions multibody/plant/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -87,27 +87,18 @@ drake_cc_library(
],
)

drake_cc_library(
name = "dummy_physical_model",
testonly = 1,
srcs = ["dummy_physical_model.cc"],
hdrs = ["dummy_physical_model.h"],
visibility = ["//visibility:private"],
deps = [
":multibody_plant_core",
],
)

drake_cc_library(
name = "multibody_plant_core",
srcs = [
"compliant_contact_manager.cc",
"deformable_driver.cc",
"deformable_model.cc",
"discrete_update_manager.cc",
"dummy_physical_model.cc",
"make_discrete_update_manager.cc",
"multibody_plant.cc",
"physical_model.cc",
"physical_model_collection.cc",
"sap_driver.cc",
"tamsi_driver.cc",
],
Expand All @@ -117,11 +108,13 @@ drake_cc_library(
"deformable_ids.h",
"deformable_model.h",
"discrete_update_manager.h",
"dummy_physical_model.h",
"make_discrete_update_manager.h",
"multibody_plant.h",
"multibody_plant_discrete_update_manager_attorney.h",
"multibody_plant_model_attorney.h",
"physical_model.h",
"physical_model_collection.h",
"sap_driver.h",
"scalar_convertible_component.h",
"tamsi_driver.h",
Expand Down Expand Up @@ -1174,7 +1167,7 @@ drake_cc_googletest(
drake_cc_googletest(
name = "multibody_plant_scalar_conversion_test",
deps = [
":dummy_physical_model",
":multibody_plant_core",
":plant",
],
)
Expand All @@ -1198,6 +1191,15 @@ drake_cc_googletest(
],
)

drake_cc_googletest(
name = "physical_model_collection_test",
deps = [
":multibody_plant_config_functions",
":multibody_plant_core",
"//common/test_utilities:expect_throws_message",
],
)

drake_cc_googletest(
name = "wing_test",
data = ["//multibody:models"],
Expand All @@ -1213,7 +1215,6 @@ drake_cc_googletest(
drake_cc_googletest(
name = "discrete_update_manager_test",
deps = [
":dummy_physical_model",
":multibody_plant_config_functions",
":multibody_plant_core",
"//common/test_utilities:eigen_matrix_compare",
Expand All @@ -1230,7 +1231,6 @@ drake_cc_googletest(
drake_cc_googletest(
name = "physical_model_test",
deps = [
":dummy_physical_model",
":multibody_plant_core",
"//common/test_utilities:eigen_matrix_compare",
"//common/test_utilities:expect_throws_message",
Expand Down
5 changes: 4 additions & 1 deletion multibody/plant/physical_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,13 @@ class PhysicalModel : public internal::ScalarConvertibleComponent<T> {
return DoToPhysicalModelPointerVariant();
}

protected:
/* Returns the back pointer to the MultibodyPlant owning `this`
PhysicalModel pre-finalize and nullptr post-finalize. */
const MultibodyPlant<T>* plant() const { return owning_plant_; }

protected:
/* Returns the mutable back pointer to the MultibodyPlant owning `this`
PhysicalModel pre-finalize and nullptr post-finalize. */
MultibodyPlant<T>* mutable_plant() { return owning_plant_; }

/* Derived classes must override this function to return their specific model
Expand Down
71 changes: 71 additions & 0 deletions multibody/plant/physical_model_collection.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include "drake/multibody/plant/physical_model_collection.h"

namespace drake {
namespace multibody {
namespace internal {

template <typename T>
DeformableModel<T>& PhysicalModelCollection<T>::AddDeformableModel(
std::unique_ptr<DeformableModel<T>> model) {
DRAKE_THROW_UNLESS(deformable_model_ == nullptr);
DRAKE_THROW_UNLESS(model != nullptr);
DRAKE_THROW_UNLESS(model->plant() == plant());
deformable_model_ = model.get();
owned_models_.emplace_back(std::move(model));
return *deformable_model_;
}

template <typename T>
DummyPhysicalModel<T>& PhysicalModelCollection<T>::AddDummyModel(
std::unique_ptr<DummyPhysicalModel<T>> model) {
DRAKE_THROW_UNLESS(dummy_model_ == nullptr);
DRAKE_THROW_UNLESS(model != nullptr);
DRAKE_THROW_UNLESS(model->plant() == plant());
dummy_model_ = model.get();
owned_models_.emplace_back(std::move(model));
return *dummy_model_;
}
template <typename T>
bool PhysicalModelCollection<T>::is_cloneable_to_double() const {
for (const auto& model : owned_models_) {
if (!model->is_cloneable_to_double()) {
return false;
}
}
return true;
}

template <typename T>
bool PhysicalModelCollection<T>::is_cloneable_to_autodiff() const {
for (const auto& model : owned_models_) {
if (!model->is_cloneable_to_autodiff()) {
return false;
}
}
return true;
}

template <typename T>
bool PhysicalModelCollection<T>::is_cloneable_to_symbolic() const {
for (const auto& model : owned_models_) {
if (!model->is_cloneable_to_symbolic()) {
return false;
}
}
return true;
}

template <typename T>
void PhysicalModelCollection<T>::DeclareSystemResources() {
for (auto& model : owned_models_) {
model->DeclareSystemResources();
}
owning_plant_ = nullptr;
}

} // namespace internal
} // namespace multibody
} // namespace drake

DRAKE_DEFINE_CLASS_TEMPLATE_INSTANTIATIONS_ON_DEFAULT_SCALARS(
class drake::multibody::internal::PhysicalModelCollection)
147 changes: 147 additions & 0 deletions multibody/plant/physical_model_collection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#pragma once

#include <memory>
#include <utility>
#include <vector>

#include "drake/multibody/plant/deformable_model.h"
#include "drake/multibody/plant/dummy_physical_model.h"
#include "drake/multibody/plant/physical_model.h"

namespace drake {
namespace multibody {

template <typename T>
class MultibodyPlant;

namespace internal {

/* A PhysicalModelCollection is a scalar convertible component of a
MultibodyPlant. Each MultibodyPlant owns exactly one PhysicalModelCollection.
It helps its owning MultibodyPlant manage its PhysicalModel components and
ensures that each type of PhysicalModel appears at most once in the
MultibodyPlant. PhysicalModels can be added prior to the call to
`DeclareSystemResources`. Once `DeclareSystemResources` is called, a
PhysicalModelCollection is considered to be "finalized" and new PhysicalModels
can no longer be added. The collection of PhysicalModel types is closed and
currently the only two types are DeformableModel and DummyPhysicalModel. */
template <typename T>
class PhysicalModelCollection : public ScalarConvertibleComponent<T> {
public:
DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(PhysicalModelCollection);

/* Constructs a PhysicalModelCollection owned by the given `plant`. The given
`plant` must outlive `this` PhysicalModelCollection.
@pre plant != nullptr */
explicit PhysicalModelCollection(const MultibodyPlant<T>* plant)
: owning_plant_(plant) {
DRAKE_DEMAND(plant != nullptr);
}

~PhysicalModelCollection() = default;

/* Returns the back pointer to the MultibodyPlant owning `this` PhysicalModel
before DeclareSystemResources() are called and nullptr after. */
const MultibodyPlant<T>* plant() const { return owning_plant_; }

/* Adds a DeformableModel to the collection and returns the added model if
successful.
@throws std::exception if a DeformableModel is already in the collection.
@throws std::exception if model is nullptr.
@throws std::exception if model->plant() != plant(). */
DeformableModel<T>& AddDeformableModel(
std::unique_ptr<DeformableModel<T>> model);

/* (For testing only) Adds a DummyPhysicalModel to the collection and returns
the added model if successful.
@throws std::exception if a DummyPhysicalModel is already in the collection.
@throws std::exception if model is nullptr.
@throws std::exception if model->plant() != plant(). */
DummyPhysicalModel<T>& AddDummyModel(
std::unique_ptr<DummyPhysicalModel<T>> model);

/* Returns a pointer to the stored DeformableModel if one exists and nullptr
otherwise. */
const DeformableModel<T>* deformable_model() const {
return deformable_model_;
}
DeformableModel<T>* mutable_deformable_model() { return deformable_model_; }

/* Returns a pointer to the stored DummyPhysicalModel if one exists and
nullptr otherwise. */
const internal::DummyPhysicalModel<T>* dummy_model() const {
return dummy_model_;
}
internal::DummyPhysicalModel<T>* mutable_dummy_model() {
return dummy_model_;
}

const std::vector<std::unique_ptr<PhysicalModel<T>>>& owned_models() const {
return owned_models_;
}

bool is_cloneable_to_double() const override;

bool is_cloneable_to_autodiff() const override;

bool is_cloneable_to_symbolic() const override;

/* Declare system resources on all owned models and nulls the back pointer to
the owning plant. For each PhysicalModelCollection object, this function
should be called once and only once by the owning plant, typically in the
process of MultibodyPlant::Finalize(). After the call to this function, new
models can no longer be added to `this` PhysicalModelCollection. */
void DeclareSystemResources();

/* Creates a clone of `this` PhysicalModelCollection with the scalar type
`ScalarType`. The clone should be a deep scalar conversion of the original
PhysicalModelCollection with the exception of back pointer to the owning
plant. This function should only called from the scalar conversion
constructor of MultibodyPlant, with `new_plant` being the scalar converted
MultibodyPlant under construction.
@tparam ScalarType double, AutoDiffXd, or symbolic::Expression.
@param[in] new_plant pointer to the MultibodyPlant that will own the cloned
PhysicalModelCollection. Note that we take a mutable pointer to
MultibodyPlant here as required by cloning each individual PhysicalModel.
@throw std::exception if plant is nullptr.
@throw std::exception if DeclareSystemResources() has not been called on
`this` PhysicalModelCollection
@note `DeclareSystemResources()` is not called on the clone and needs to be
called from the plant owning the clone. */
template <typename ScalarType>
std::unique_ptr<PhysicalModelCollection<ScalarType>> CloneToScalar(
MultibodyPlant<ScalarType>* new_plant) const {
DRAKE_THROW_UNLESS(owning_plant_ == nullptr);
std::unique_ptr<PhysicalModelCollection<ScalarType>> clone =
std::make_unique<PhysicalModelCollection<ScalarType>>(new_plant);
if (deformable_model_) {
auto deformable_model_clone =
std::unique_ptr<DeformableModel<ScalarType>>(
static_cast<DeformableModel<ScalarType>*>(
deformable_model_
->template CloneToScalar<ScalarType>(new_plant)
.release()));
clone->AddDeformableModel(std::move(deformable_model_clone));
}
if (dummy_model_) {
auto dummy_model_clone = std::unique_ptr<DummyPhysicalModel<ScalarType>>(
static_cast<DummyPhysicalModel<ScalarType>*>(
dummy_model_->template CloneToScalar<ScalarType>(new_plant)
.release()));
clone->AddDummyModel(std::move(dummy_model_clone));
}
return clone;
}

private:
const MultibodyPlant<T>* owning_plant_{nullptr};
/* We maintain the invariant such that each `model` in `owned_models_`
satisfies `model->plant() == owning_plant_`. */
std::vector<std::unique_ptr<PhysicalModel<T>>> owned_models_;
DeformableModel<T>* deformable_model_{nullptr};
DummyPhysicalModel<T>* dummy_model_{nullptr};
};

} // namespace internal
} // namespace multibody
} // namespace drake
Loading

0 comments on commit 2a544cc

Please sign in to comment.