User login

Navigation

You are here

The factory idiom and material models

I'm leaving the US in a couple of days and will probably take a hiatus of a few months from iMechanica.  Before I leave, I want to tell you about a C++ idiom that eases the implementation and use of multiple material models in a computational mechanics code.

The first book on C++ idioms was by Jim Copilien sometime in the late 1990s called "Advanced C++: Programming Styles and Idioms".  The idea of such idioms has become considerably widespread since then - so much so that there is a Wikibook on the subject .

The idiom I am going to talk about is the Factory idiom

My need to use the factory idiom arose when I was trying to compare a number of plasticity models.  I wanted to avoid complicating the code by using if statements or other manual control mechanisms to deal with models specified in the input. 

Let me show you how it's done - step by step.  For simplicity, let us assume that only the flow stress model varies and everything else remains the same.

Step 1:  We create a abstract base class called FlowStressModel.h.  

The contents of the file are of the form:

class FlowStressModel {

  private:

  public:

    FlowStressModel();

    virtual ~FlowStressModel();

    virtual double computeFlowStress(const PlasticityState* state, ...) = 0;

    virtual double computeDsigDep(const PlasticityState* state, ...) = 0;

};

In the corresponding FlowStressModel.cc file we have

#include "FlowStressModel.h" 

FlowStressModel::FlowStressModel() {}

FlowStressModel::~FlowStressModel() {}

Step 2:  Next we create a factory for flow stress models called FlowStressModelFactory.h

This file contains something like

class FlowStressModel;

class FlowStressModelFactory
{
  public:
     static PlasticityModel* create(ProblemSpecP& ps);
};

Here the problem specification (ProblemSpec) is a pointer to the input XML file or any other input format that you may have.

The implementation of the factory in the file FlowStressModelFactory.cc has the following form

#include "FlowStressModelFactory.h"

#include "LinearHardeningPlasticity.h"

#include "JohnsonCookPlasticity.h"

.... 

FlowStressModel* FlowStressModelFactory::create(ProblemSpecP& ps)

{

  // First read the problem specification (however you want)

  // and get the material_type (mat_type)

  if (mat_type == "linear hardening") {

     return (new LinearHardeningPlasticity(ps));

  } else if (mat_type == "johnson_cook") {

    return (new JohnsonCookPlasticity(ps));

  } 

Step 3:  Now we can implement the LinearHardeningPlasticity and JohnsonCookPlasticity models by deriving them from the FlowStressModel class and making them concrete.  For instance, for the JohnsonCookPlasticity model we have a JohnsonCookPlasticity.h file which contains

#include "FlowStressModel.h"

class JohnsonCookPlasticity : public FlowStressModel

{

  private:

    LocalModelData d_data;

  public:

    JohsonCookPlasticity(ProblemSpecP& ps);

   virtual ~JohnsonCookPlasticity();

   double computeFlowStress(const PlasticityState* state, ...);

   double computeDsigDep(const PlasticityState* state, ...); 

The implementation of the model is in JohnsonCookPlasticity.cc which contains something like

#include "JohnsonCookPlasticity.h"

JohnsonCookPlasticity::JohnsonCookPlasticity(ProblemSpecP& ps)

{

   // Read stuff from the input file and create object 

JohnsonCookPlasticity::~JohnsonCookPlasticity()

{

   // delete anything that you need to

double 

JohnsonCookPlasticity::computeFlowStress(const PlasticityState* state, ...)

{

   // do tha actual flow stress computation here 

double

JohnsonCookPlasticity:: computeDsigDep(const PlasticityState* state, ...)

{

  // Calculate the derivative of the flow stress with respect to the plastic strain
 

Adding other flow stress models follows the same pattern.  All you have to do is create the code for the model and add a line to the factory. 

Step 4: The final step is to add this information to your elastic-plastic stress update code.  Let us suppose that the class is called ElasticPlastic.  Then the file ElasticPlastic.h will have the form 

#include "FlowStressModel.h"

.....

class ElasticPlastic {

  public:

    .....

  protected:

    FlowStressModel* d_flowStress;

    .....

  public:

    ElasticPlastic(ProblemSpecP& ps);

    ~ElasticPlastic();

    void computeStress(Matrix& stress);

    ......

}; 

In the actual implementation of ElasticPlastic (i.e., in the ElasticPlastic.cc file) you will have

#include "ElasticPlastic.h"

#include "FlowStressModelFactory.h"

...

ElasticPlastic::ElasticPlastic(ProblemSpecP& ps)

{

  // Read all the other stuff that you need for the ElasticPlastic model 

  // Create the flow stress model

  d_flowStress = FlowStressModelFactory::create(ps);

ElasticPlastic::~ElasticPlastic()

{

  // Delete all the other stuff that you need to delete

  // Delete the flow stres model

  delete d_flowStress;

}

void

ElasticPlastic::compute stress(Matrix& stress)

{

   // Do whatever is needed before you can compute the flow stress

   // set up the plasticity state

  PlasticityState* state = new PlasticityState(); 

  // compute the flow stress

  double flowStress = d_flowStress->computeFlowStress(state, ....);

So you have made the code much more cleaner than otherwise possible and more intuitive. 

That's the basic idea which we use extensively in Uintah.  Our inputs files are in XML and hundreds of material models can be easily switched in and out without the user or the coder having to bother at all with whether the if statements are correctly done.  For instance if the original input file contained something like

          <flow_stress_model type = "johnson_cook">
            <A> 90.0e6  </A>
            <B> 292.0e6 </B>
            <C> 0.025   </C>
            <n> 0.31    </n>
            <m> 1.09    </m>
          </flow_stress_model>

then all the user needs to do to switch to a linear hardening model is write instead

          <flow_stress_model type = "linear_hardening">
            <sig_0> 90.0e6  </sig_0>
            <H> 292.0e5 </H>
          </plasticity_model>

and everything exactly as before - but with a new model.

Hope that helps some of you out there.

-- Biswajit 

 

Comments

Zhigang Suo's picture

Dear Biswajit:  Thank you so much for your contributions to iMechanica.  I have learned much from you.  Please let us know when you are settled in your new environment.  Good Luck and best wishes, Zhigang

Dear Biswajit,

Good that you broached this topic up... I was wondering if discussions related to programming would be appropriate here at iMechanica---especially, discussions at a somewhat more abstract level (i.e. not concerned with the syntax of languages etc.)... Also, the more serious amongst tutorial codes in C++... I was already wondering if I should be posting some of my code my general blog site... So, I was really delighted to see your above post here...

About C++ idioms. A very closely related topic is Design Patterns. For example, see here and here.

With that said, I have a word of caution, though. IMO it is best *NOT* to try to use design patterns right in the first iteration of a major version of your software--v 1.0 or v 2.0 or whatever....

I know I am sounding like an unenthusiastic fool who has no respect whatsoever for the abstract or high-level design here... But the way I loook at it, there has been sometimes too much of a good thing w.r.t. the high-level abstract design too... Just for example, notice that issues and factors such as data locality (cache and virtual memory), ease of IPC and of parallelization, etc. ought to enter software design... Yet, as a matter of fact, a lot of issues of this nature cannot become as clear as they should be, until the first cut is already over. (We don't have to wait until the profiling stage, but at least a major chunk of the code ought to first exist before people can really get such parts right.) Hence, it is sometimes better to go ahead with a simple scheme involving a minimal number of very loosely coupled classes, and then put them all together into a better framework... A real bottom-up design exercise, in a sense....

Of course, my above comment does not apply to your above post of C++ idioms (or your example of the Factory idiom)... I just wanted to qualify my recommendation of design patterns, that's all...

-----

Biswajit, on a personal note: If you want to quit USA, that's good (ask me why (!)) but you don't want to therefore return to India, do you?

One way or the other, I enjoyed your answers over a range of issues here... Let me wish you the very best in your new environment, and, as Zhigang said, do let us know once you are ready to chat here at iMechanica again... I look forward to interacting with you soon again...

--Ajit

Teng Li's picture

Dear Biswajit, 

Wish you the best in your new post, and we look forward to your coming back to iMechanica. 

-Teng 

N. Sukumar's picture

Good luck, Biswajit. A C++ library that contains implementations of design patterns and idioms is Loki.

Subscribe to Comments for "The factory idiom and material models"

More comments

Syndicate

Subscribe to Syndicate