Skip to content

Extending the Library

This page shows how to create a custom micromechanical model in Python and C++.

Note

In C++, make sure to add the following include directories of the micromechanical library and the Eigen library to the include directories of your compiler:

micromechanical/cpp/include
micromechanical/cpp/deps/eigen

Define the micromechanical model

To create a custom micromechanical model, first create a class that inherits from the MicromechanicalBase class or one of its subclasses. Check ChangHicherAbstractModel for an example of the Chang-Hicher model. The following code only shows the class inheritance:

from micromechanical.python.micromechanical.core.average import LoveWeberAveraging, BestFitAveraging
from micromechanical.python.micromechanical.core.localize import KinematicHypothesisLocalization, StaticHypothesisLocalization
from micromechanical.python.micromechanical.core.mixedload import MixedLoadControl

class ChangHicherAbstractModel(
    MixedLoadControl,
    LoveWeberAveraging,
    BestFitAveraging,
    StaticHypothesisLocalization,
    KinematicHypothesisLocalization,
):
    ...
#include <micromechanical/core/average.hpp>
#include <micromechanical/core/localize.hpp>
#include <micromechanical/core/mixedload.hpp>

using namespace micromechanical::core;

template <typename T = double>
struct ChangHicher : public MixedLoadControl<T>,
                     public LoveWeberAveraging<T>,
                     public BestFitAveraging<T>,
                     public StaticHypothesisLocalization<T>,
                     public KinematicHypothesisLocalization<T> {};

Define the contact law

After that, define the contact law for the micromechanical model. To do so, create a class that inherits from the NonlinearElasticContactLaw class to define a nonlinear elastic contact law, or ElastoplasticContactLaw class to define an elastoplastic contact law. For example, the following code defines an elastic contact law:

import numpy as np

from micromechanical.python.micromechanical.contacts.register import contact_registry
from micromechanical.python.micromechanical.core.contactlaw import NonlinearElasticContactLaw
from micromechanical.python.micromechanical.core.stiffness import ConstantStiffness
from micromechanical.python.micromechanical.core.statevariable import StateVariable
from micromechanical.numba import numba
from micromechanical.registry import register

@register("Elastic", saveto=contact_registry)
@numba.experimental.jitclass
class ElasticContactLaw(NonlinearElasticContactLaw, ConstantStiffness):

    def stiffness(self, idx: int, ddisp: np.ndarray, sv: StateVariable) -> np.ndarray:
        return sv.elasticStiffnessMatrix()
#include <micromechanical/core/contactlaw.hpp>
#include <micromechanical/core/stiffness.hpp>
#include <micromechanical/core/statevariable.hpp>

using namespace micromechanical::core;

template <typename T = double>
class ElasticContactLaw : public NonlinearElasticContactLaw<T>, public ConstantStiffness<T> {

    Eigen::Matrix<T, 3, 3> stiffness(int idx, const Eigen::Matrix<T, 3, 1>& ddisp,
                                     StateVariable<T>& sv) const override {
        return sv.elasticStiffnessMatrix();
    }
}

Then, define the contact law for the micromechanical model. To do so, create a class that inherits from the class you defined above. Then, register the class with register decorator. For example, the following code defines the Chang-Hicher model with an elastic contact law:

from micromechanical.python.micromechanical.changhicher import ChangHicherAbstractModel
from micromechanical.python.micromechanical.contacts.elastic import ElasticContactLaw
from micromechanical.python.micromechanical.registry import micromechanical_registry
from micromechanical.numba import numba
from micromechanical.registry import register

@register("ChangHicher-Elastic", saveto=micromechanical_registry)
@numba.experimental.jitclass
class ChangHicherElasticModel(ChangHicherAbstractModel):
    """Chang-Hicher model with the elastic contact law."""

    contact: ElasticContactLaw

    def createContactLaw(self, props: dict[str, float] = None):
        return ElasticContactLaw(props)

Note

In C++ backend, you don't have to create a new class to link the contact law to the micromechanical model. You can simply pass a pointer to the contact law to the constructor of the micromechanical model. For example:

#include <micromechanical/changhicher.hpp>
#include <micromechanical/contacts/elastic.hpp>

using namespace micromechanical;
using namespace micromechanical::contacts;

auto *contact = new ElasticContactLaw<double>();
auto *model = new ChangHicher<double>(contact);

Instantiate the micromechanical model

After registering the class, you can now pass the instance of the class or the custom model name to the Model class to create a micromechanical model instance.

from micromechanical import Model

model = Model("ChangHicher-Elastic")

Or pass an instance of the class you defined above to the Model class.

from micromechanical import Model
from micromechanical.python.micromechanical.changhicher import ChangHicherElasticModel

model = Model(ChangHicherElasticModel())
from micromechanical import Model
from micromechanical.cppbind.micromechanical import ChangHicherd
from micromechanical.cppbind.micromechanical.contacts import ElasticContactLawd

contact = ElasticContactLawd()
model = Model(ChangHicherd(contact))