diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bef61cc..ebad8dd0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,8 @@ set(NEML_version 1.4.1) ### Setup modules ### set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") -### Need c++ 11 ### -set(CMAKE_CXX_STANDARD 11) +### Need c++ 17 ### +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) ### Default to shared libs ### diff --git a/include/cp/crystaldamage.h b/include/cp/crystaldamage.h index f9aa789b..b78ce9e3 100644 --- a/include/cp/crystaldamage.h +++ b/include/cp/crystaldamage.h @@ -17,7 +17,7 @@ class SlipPlaneDamage; class TransformationFunction; /// Abstract base class for slip plane damage models -class NEML_EXPORT CrystalDamageModel: public NEMLObject { +class NEML_EXPORT CrystalDamageModel: public HistoryNEMLObject { public: CrystalDamageModel(ParameterSet & params, std::vector vars); @@ -32,9 +32,9 @@ class NEML_EXPORT CrystalDamageModel: public NEMLObject { virtual void set_varnames(std::vector names); /// Setup whatever history variables the model requires - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Initialize history - virtual void init_history(History & history) const = 0; + virtual void init_hist(History & history) const = 0; /// Returns the current projection operator virtual SymSymR4 projection( @@ -85,7 +85,7 @@ class NEML_EXPORT NilDamageModel: public CrystalDamageModel { static ParameterSet parameters(); /// Initialize history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Returns the current projection operator virtual SymSymR4 projection( @@ -136,7 +136,7 @@ class NEML_EXPORT PlanarDamageModel: public CrystalDamageModel { static ParameterSet parameters(); /// Initialize history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Returns the current projection operator virtual SymSymR4 projection( diff --git a/include/cp/hucocks.h b/include/cp/hucocks.h index fa7a0100..5666b2b3 100644 --- a/include/cp/hucocks.h +++ b/include/cp/hucocks.h @@ -12,7 +12,7 @@ namespace neml { /// Implementation of a single chemistry <-> size model // For details see Hu et al. MSE A, 2020 -class NEML_EXPORT HuCocksPrecipitationModel: public NEMLObject +class NEML_EXPORT HuCocksPrecipitationModel: public HistoryNEMLObject { public: HuCocksPrecipitationModel(ParameterSet & params); @@ -30,9 +30,9 @@ class NEML_EXPORT HuCocksPrecipitationModel: public NEMLObject virtual void set_varnames(std::vector vars); /// Request whatever history you will need - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Setup history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Actual (unscaled) f double f(const History & history) const; @@ -207,9 +207,9 @@ class NEML_EXPORT DislocationSpacingHardening: public SlipHardening virtual void set_varnames(std::vector vars); /// Request whatever history you will need - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Setup history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Map the set of history variables to the slip system hardening virtual double hist_to_tau(size_t g, size_t i, const History & history, @@ -283,9 +283,9 @@ class NEML_EXPORT HuCocksHardening: public SlipHardening virtual void set_varnames(std::vector vars); /// Request whatever history you will need - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Setup history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Map the set of history variables to the slip system hardening virtual double hist_to_tau(size_t g, size_t i, const History & history, diff --git a/include/cp/inelasticity.h b/include/cp/inelasticity.h index 74f11307..2e122d68 100644 --- a/include/cp/inelasticity.h +++ b/include/cp/inelasticity.h @@ -17,13 +17,9 @@ namespace neml { /// A inelastic model supplying D_p and W_p // A complete model for implicit rotations would include the derivatives wrt // the orientation. Similarly it would include all the w_p derivatives. -class NEML_EXPORT InelasticModel: public NEMLObject { +class NEML_EXPORT InelasticModel: public HistoryNEMLObject { public: InelasticModel(ParameterSet & params); - /// Populate a history object with the correct variables - virtual void populate_history(History & history) const = 0; - /// Actually initialize the history object with the starting values - virtual void init_history(History & history) const = 0; /// Helper for external models that want an average strength virtual double strength(const History & history, Lattice & L, double T, @@ -103,9 +99,9 @@ class NEML_EXPORT NoInelasticity: public InelasticModel { static ParameterSet parameters(); /// Add history variables (none needed) - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Define initial history (none) - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Helper for external models that want an average strength virtual double strength(const History & history, Lattice & L, double T, @@ -185,9 +181,9 @@ class NEML_EXPORT AsaroInelasticity: public InelasticModel { static ParameterSet parameters(); /// Populate the history, deferred to the SlipRule - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Initialize the history with the starting values, deferred to the SlipRule - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Helper for external models that want an average strength virtual double strength(const History & history, Lattice & L, double T, @@ -277,9 +273,9 @@ class NEML_EXPORT PowerLawInelasticity: public InelasticModel { static ParameterSet parameters(); /// Setup history variables (none used in this implementation) - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Initialize the history variables (n/a) - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Helper for external models that want an average strength virtual double strength(const History & history, Lattice & L, double T, @@ -377,9 +373,9 @@ class NEML_EXPORT CombinedInelasticity: public InelasticModel { const History & fixed) const; /// Setup all history variables - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Initialize history with actual values - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Sum the symmetric parts of the plastic deformation rates virtual Symmetric d_p(const Symmetric & stress, diff --git a/include/cp/kinematics.h b/include/cp/kinematics.h index 5d6df8da..0c701ac0 100644 --- a/include/cp/kinematics.h +++ b/include/cp/kinematics.h @@ -17,13 +17,9 @@ namespace neml { /// Describes the stress, history, and rotation rates -class NEML_EXPORT KinematicModel: public NEMLObject { +class NEML_EXPORT KinematicModel: public HistoryNEMLObject { public: KinematicModel(ParameterSet & params); - /// Populate history with the correct variable names and types - virtual void populate_history(History & history) const = 0; - /// Initialize history with actual starting values - virtual void init_history(History & history) const = 0; /// Helper for external models that want a strength virtual double strength(const History & history, Lattice & L, double T, @@ -171,9 +167,9 @@ class NEML_EXPORT StandardKinematicModel: public KinematicModel { static ParameterSet parameters(); /// Populate a history object with the correct variables - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Initialize the history object with the starting values - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Helper for external models that want a strength virtual double strength(const History & history, Lattice & L, double T, @@ -305,9 +301,9 @@ class NEML_EXPORT DamagedStandardKinematicModel: public StandardKinematicModel { static ParameterSet parameters(); /// Populate a history object with the correct variables - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Initialize the history object with the starting values - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Stress rate virtual Symmetric stress_rate( diff --git a/include/cp/polycrystal.h b/include/cp/polycrystal.h index ca1ed5a5..4eb20dca 100644 --- a/include/cp/polycrystal.h +++ b/include/cp/polycrystal.h @@ -15,9 +15,12 @@ class NEML_EXPORT PolycrystalModel: public NEMLModel_ldi PolycrystalModel(ParameterSet & params); size_t n() const; + + virtual void populate_hist(History & hist) const; + virtual void init_hist(History & hist) const; - virtual size_t nhist() const; - virtual void init_hist(double * const hist) const; + virtual void populate_state(History & hist) const {}; + virtual void init_state(History & hist) const {}; double * history(double * const store, size_t i) const; double * stress(double * const store, size_t i) const; @@ -49,9 +52,6 @@ class NEML_EXPORT TaylorModel: public PolycrystalModel /// Setup from a ParameterSet static std::unique_ptr initialize(ParameterSet & params); - virtual size_t nstore() const; - virtual void init_store(double * const store) const; - /// Large strain incremental update virtual void update_ld_inc( const double * const d_np1, const double * const d_n, diff --git a/include/cp/postprocessors.h b/include/cp/postprocessors.h index 99cc67c6..953f2b6c 100644 --- a/include/cp/postprocessors.h +++ b/include/cp/postprocessors.h @@ -16,8 +16,8 @@ class NEML_EXPORT CrystalPostprocessor: public NEMLObject { public: CrystalPostprocessor(ParameterSet & params); - virtual void populate_history(const Lattice & L, History & history) const = 0; - virtual void init_history(const Lattice & L, History & history) const = 0; + virtual void populate_hist(const Lattice & L, History & history) const = 0; + virtual void init_hist(const Lattice & L, History & history) const = 0; virtual void act(SingleCrystalModel & model, const Lattice &, const double & T, const Symmetric & D, @@ -37,8 +37,8 @@ class NEML_EXPORT PTRTwinReorientation: public CrystalPostprocessor { /// Setup from a ParameterSet static std::unique_ptr initialize(ParameterSet & params); - virtual void populate_history(const Lattice & L, History & history) const; - virtual void init_history(const Lattice & L, History & history) const; + virtual void populate_hist(const Lattice & L, History & history) const; + virtual void init_hist(const Lattice & L, History & history) const; virtual void act(SingleCrystalModel & model, const Lattice &, const double & T, const Symmetric & D, diff --git a/include/cp/singlecrystal.h b/include/cp/singlecrystal.h index 9bf8b10f..ca715c70 100644 --- a/include/cp/singlecrystal.h +++ b/include/cp/singlecrystal.h @@ -57,10 +57,14 @@ class NEML_EXPORT SingleCrystalModel: public NEMLModel_ldi, public Solvable static std::unique_ptr initialize(ParameterSet & params); /// Setup blank history - void populate_history(History & history) const; - + void populate_state(History & history) const; /// Actually initialize history - void init_history(History & history) const; + void init_state(History & history) const; + + /// Not changing state + void populate_static(History & history) const; + /// Static stat + void init_static(History & history) const; /// Useful methods for external models that want an idea of an average /// strength @@ -71,21 +75,16 @@ class NEML_EXPORT SingleCrystalModel: public NEMLModel_ldi, public Solvable double * Fe) const; /// Large deformation incremental update - virtual void update_ld_inc( - const double * const d_np1, const double * const d_n, - const double * const w_np1, const double * const w_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, double * const B_np1, - double & u_np1, double u_n, - double & p_np1, double p_n); - - /// Number of stored history variables - virtual size_t nhist() const; - /// Initialize history raw pointer array - virtual void init_hist(double * const hist) const; + virtual void update_ld_inc_interface( + const Symmetric & d_np1, const Symmetric & d_n, + const Skew & w_np1, const Skew & w_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, SymSkewR4 & B_np1, + double & u_np1, double u_n, + double & p_np1, double p_n); /// Instantaneous CTE virtual double alpha(double T) const; @@ -129,19 +128,15 @@ class NEML_EXPORT SingleCrystalModel: public NEMLModel_ldi, public Solvable private: void attempt_update_ld_inc_( - const double * const d_np1, const double * const d_n, - const double * const w_np1, const double * const w_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, double * const B_np1, - double & u_np1, double u_n, - double & p_np1, double p_n, int trial_type); - - History gather_history_(double * data) const; - History gather_history_(const double * data) const; - History gather_blank_history_() const; + const Symmetric & d_np1, const Symmetric & d_n, + const Skew & w_np1, const Skew & w_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, SymSkewR4 & B_np1, + double & u_np1, double u_n, + double & p_np1, double p_n, int trial_type); void calc_tangents_(Symmetric & S, History & H, SCTrialState * ts, double * const A, double * const B); @@ -156,10 +151,6 @@ class NEML_EXPORT SingleCrystalModel: public NEMLModel_ldi, public Solvable void solve_substep_(SCTrialState * ts, Symmetric & stress, History & hist); - std::vector not_updated_() const; - - void populate_static_(History & history) const; - private: std::shared_ptr kinematics_; std::shared_ptr lattice_; @@ -171,11 +162,7 @@ class NEML_EXPORT SingleCrystalModel: public NEMLModel_ldi, public Solvable bool verbose_, linesearch_; int max_divide_; - History stored_hist_; - std::vector> postprocessors_; - std::vector static_names_; - size_t static_size_; bool elastic_predictor_, fallback_elastic_predictor_; int force_divide_; diff --git a/include/cp/slipharden.h b/include/cp/slipharden.h index 1cbe87e8..7316cdcf 100644 --- a/include/cp/slipharden.h +++ b/include/cp/slipharden.h @@ -23,7 +23,7 @@ namespace neml { class SlipRule; // Why would we need a forward declaration? /// ABC for a slip hardening model -class NEML_EXPORT SlipHardening: public NEMLObject +class NEML_EXPORT SlipHardening: public HistoryNEMLObject { public: SlipHardening(ParameterSet & params); @@ -32,11 +32,6 @@ class NEML_EXPORT SlipHardening: public NEMLObject /// Set new varnames virtual void set_varnames(std::vector vars) = 0; - /// Request whatever history you will need - virtual void populate_history(History & history) const = 0; - /// Setup history - virtual void init_history(History & history) const = 0; - /// Map the set of history variables to the slip system hardening virtual double hist_to_tau(size_t g, size_t i, const History & history, Lattice & L, @@ -116,9 +111,9 @@ class NEML_EXPORT FixedStrengthHardening: public SlipHardening virtual void set_varnames(std::vector vars); /// Request whatever history you will need - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Setup history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Map the set of history variables to the slip system hardening virtual double hist_to_tau(size_t g, size_t i, const History & history, @@ -174,9 +169,9 @@ class NEML_EXPORT VocePerSystemHardening: public SlipHardening virtual void set_varnames(std::vector vars); /// Request whatever history you will need - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Setup history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Map the set of history variables to the slip system hardening virtual double hist_to_tau(size_t g, size_t i, const History & history, @@ -239,9 +234,9 @@ class NEML_EXPORT FASlipHardening: public SlipHardening virtual void set_varnames(std::vector vars); /// Request whatever history you will need - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Setup history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Map the set of history variables to the slip system hardening virtual double hist_to_tau(size_t g, size_t i, const History & history, @@ -303,9 +298,9 @@ class NEML_EXPORT GeneralLinearHardening: public SlipHardening virtual void set_varnames(std::vector vars); /// Request whatever history you will need - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Setup history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Map the set of history variables to the slip system hardening virtual double hist_to_tau(size_t g, size_t i, const History & history, @@ -380,9 +375,9 @@ class NEML_EXPORT SimpleLinearHardening: public SlipHardening virtual void set_varnames(std::vector vars); /// Request whatever history you will need - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Setup history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Map the set of history variables to the slip system hardening virtual double hist_to_tau(size_t g, size_t i, const History & history, @@ -454,9 +449,9 @@ class NEML_EXPORT LANLTiModel: public SlipHardening virtual void set_varnames(std::vector vars); /// Request whatever history you will need - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Setup history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Map the set of history variables to the slip system hardening virtual double hist_to_tau(size_t g, size_t i, const History & history, @@ -550,9 +545,9 @@ class NEML_EXPORT SlipSingleStrengthHardening: public SlipSingleHardening virtual void set_varnames(std::vector vars); /// Request whatever history you will need - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Setup history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// The rate of the history virtual History hist(const Symmetric & stress, @@ -656,9 +651,9 @@ class NEML_EXPORT SumSlipSingleStrengthHardening: public SlipSingleHardening static ParameterSet parameters(); /// Request whatever history you will need - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Setup history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// The rate of the history virtual History hist(const Symmetric & stress, diff --git a/include/cp/sliprules.h b/include/cp/sliprules.h index 04a11d25..0dfde2ed 100644 --- a/include/cp/sliprules.h +++ b/include/cp/sliprules.h @@ -23,14 +23,10 @@ namespace neml { class SlipHardening; /// Abstract base class for a slip rule -class NEML_EXPORT SlipRule: public NEMLObject +class NEML_EXPORT SlipRule: public HistoryNEMLObject { public: SlipRule(ParameterSet & params); - /// Populate the history object with the appropriate variable names and types - virtual void populate_history(History & history) const = 0; - /// Actually set the history to their initial values - virtual void init_history(History & history) const = 0; /// Helper for models that want an average strength virtual double strength(const History & history, Lattice & L, double T, @@ -95,9 +91,9 @@ class NEML_EXPORT SlipMultiStrengthSlipRule: public SlipRule size_t nstrength() const; /// Populate the history - virtual void populate_history(History & history) const; + virtual void populate_hist(History & history) const; /// Actually initialize the history - virtual void init_history(History & history) const; + virtual void init_hist(History & history) const; /// Helper for models that want an average strength virtual double strength(const History & history, Lattice & L, double T, diff --git a/include/creep.h b/include/creep.h index 877f70dd..8fc77c77 100644 --- a/include/creep.h +++ b/include/creep.h @@ -16,20 +16,15 @@ class NEML_EXPORT ScalarCreepRule: public NEMLObject { ScalarCreepRule(ParameterSet & params); /// Scalar creep strain rate as a function of effective stress, /// effective strain, time, and temperature - virtual void g(double seq, double eeq, double t, double T, double & g) - const = 0; + virtual double g(double seq, double eeq, double t, double T) const = 0; /// Derivative of scalar creep rate wrt effective stress - virtual void dg_ds(double seq, double eeq, double t, double T, double & dg) - const = 0; + virtual double dg_ds(double seq, double eeq, double t, double T) const = 0; /// Derivative of scalar creep rate wrt effective strain - virtual void dg_de(double seq, double eeq, double t, double T, double & dg) - const = 0; + virtual double dg_de(double seq, double eeq, double t, double T) const = 0; /// Derivative of scalar creep rate wrt time, defaults to zero - virtual void dg_dt(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_dt(double seq, double eeq, double t, double T) const; /// Derivative of scalar creep rate wrt temperature, defaults to zero - virtual void dg_dT(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_dT(double seq, double eeq, double t, double T) const; }; /// Creep rate law from Blackburn 1972 @@ -45,16 +40,13 @@ class NEML_EXPORT BlackburnMinimumCreep: public ScalarCreepRule { static ParameterSet parameters(); /// rate = A * (sinh(beta*s/n)^n * exp(-Q/(R*T)) - virtual void g(double seq, double eeq, double t, double T, double & g) const; + virtual double g(double seq, double eeq, double t, double T) const; /// Derivative of rate wrt effective stress - virtual void dg_ds(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_ds(double seq, double eeq, double t, double T) const; /// Derivative of rate wrt effective strain = 0 - virtual void dg_de(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_de(double seq, double eeq, double t, double T) const; /// Derivative of rate wrt temperature - virtual void dg_dT(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_dT(double seq, double eeq, double t, double T) const; private: const std::shared_ptr A_, n_, beta_; @@ -76,16 +68,13 @@ class NEML_EXPORT SwindemanMinimumCreep: public ScalarCreepRule { static ParameterSet parameters(); /// rate = C * S^n * exp(V*S) * exp(-Q/T) - virtual void g(double seq, double eeq, double t, double T, double & g) const; + virtual double g(double seq, double eeq, double t, double T) const; /// Derivative of rate wrt effective stress - virtual void dg_ds(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_ds(double seq, double eeq, double t, double T) const; /// Derivative of rate wrt effective strain = 0 - virtual void dg_de(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_de(double seq, double eeq, double t, double T) const; /// Derivative of rate wrt temperature - virtual void dg_dT(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_dT(double seq, double eeq, double t, double T) const; private: const double C_, n_, V_, Q_, shift_; @@ -107,13 +96,11 @@ class NEML_EXPORT PowerLawCreep: public ScalarCreepRule { static ParameterSet parameters(); /// rate = A * seq**n - virtual void g(double seq, double eeq, double t, double T, double & g) const; + virtual double g(double seq, double eeq, double t, double T) const; /// Derivative of rate wrt effective stress - virtual void dg_ds(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_ds(double seq, double eeq, double t, double T) const; /// Derivative of rate wrt effective strain = 0 - virtual void dg_de(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_de(double seq, double eeq, double t, double T) const; /// Getter for the prefactor double A(double T) const; @@ -140,13 +127,11 @@ class NEML_EXPORT NormalizedPowerLawCreep: public ScalarCreepRule { static ParameterSet parameters(); /// rate = (seq/s0)**n - virtual void g(double seq, double eeq, double t, double T, double & g) const; + virtual double g(double seq, double eeq, double t, double T) const; /// Derivative of rate wrt effective stress - virtual void dg_ds(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_ds(double seq, double eeq, double t, double T) const; /// Derivative of rate wrt effective strain = 0 - virtual void dg_de(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_de(double seq, double eeq, double t, double T) const; private: const std::shared_ptr s0_, n_; @@ -170,11 +155,11 @@ class NEML_EXPORT RegionKMCreep: public ScalarCreepRule { static ParameterSet parameters(); /// See documentation for details of the creep rate - virtual void g(double seq, double eeq, double t, double T, double & g) const; - /// Derivative of creep rate wrt effective stress - virtual void dg_ds(double seq, double eeq, double t, double T, double & dg) const; - /// Derivative of creep rate wrt effective strain - virtual void dg_de(double seq, double eeq, double t, double T, double & dg) const; + virtual double g(double seq, double eeq, double t, double T) const; + /// Derivative of rate wrt effective stress + virtual double dg_ds(double seq, double eeq, double t, double T) const; + /// Derivative of rate wrt effective strain = 0 + virtual double dg_de(double seq, double eeq, double t, double T) const; private: void select_region_(double seq, double T, double & Ai, double & Bi) const; @@ -204,11 +189,11 @@ class NEML_EXPORT NortonBaileyCreep: public ScalarCreepRule { static ParameterSet parameters(); /// creep rate = m * A**(1/m) * seq**(n/m) * eeq ** ((m-1)/m) - virtual void g(double seq, double eeq, double t, double T, double & g) const; - /// Derivative of creep rate wrt effective stress - virtual void dg_ds(double seq, double eeq, double t, double T, double & dg) const; - /// Derivative of creep rate wrt effective strain - virtual void dg_de(double seq, double eeq, double t, double T, double & dg) const; + virtual double g(double seq, double eeq, double t, double T) const; + /// Derivative of rate wrt effective stress + virtual double dg_ds(double seq, double eeq, double t, double T) const; + /// Derivative of rate wrt effective strain = 0 + virtual double dg_de(double seq, double eeq, double t, double T) const; /// Getter for the prefactor double A(double T) const; @@ -240,11 +225,11 @@ class NEML_EXPORT MukherjeeCreep: public ScalarCreepRule { /// scalar creep rate = A * D0 * exp(Q / (RT)) * mu * b / (k * T) * /// (seq / mu)**n - virtual void g(double seq, double eeq, double t, double T, double & g) const; - /// Derivative of creep rate wrt effective stress - virtual void dg_ds(double seq, double eeq, double t, double T, double & dg) const; - /// Derivative of creep rate wrt effective strain - virtual void dg_de(double seq, double eeq, double t, double T, double & dg) const; + virtual double g(double seq, double eeq, double t, double T) const; + /// Derivative of rate wrt effective stress + virtual double dg_ds(double seq, double eeq, double t, double T) const; + /// Derivative of rate wrt effective strain = 0 + virtual double dg_de(double seq, double eeq, double t, double T) const; /// Getter for A double A() const; @@ -282,11 +267,11 @@ class NEML_EXPORT GenericCreep: public ScalarCreepRule { static ParameterSet parameters(); /// scalar creep rate = exp(f(log(sigma))) - virtual void g(double seq, double eeq, double t, double T, double & g) const; - /// Derivative of creep rate wrt effective stress - virtual void dg_ds(double seq, double eeq, double t, double T, double & dg) const; - /// Derivative of creep rate wrt effective strain - virtual void dg_de(double seq, double eeq, double t, double T, double & dg) const; + virtual double g(double seq, double eeq, double t, double T) const; + /// Derivative of rate wrt effective stress + virtual double dg_ds(double seq, double eeq, double t, double T) const; + /// Derivative of rate wrt effective strain = 0 + virtual double dg_de(double seq, double eeq, double t, double T) const; private: const std::shared_ptr cfn_; @@ -309,13 +294,11 @@ class NEML_EXPORT MinCreep225Cr1MoCreep: public ScalarCreepRule { static ParameterSet parameters(); /// See documentation for the hideous formula - virtual void g(double seq, double eeq, double t, double T, double & g) const; + virtual double g(double seq, double eeq, double t, double T) const; /// Derivative of rate wrt effective stress - virtual void dg_ds(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_ds(double seq, double eeq, double t, double T) const; /// Derivative of rate wrt effective strain = 0 - virtual void dg_de(double seq, double eeq, double t, double T, double & dg) - const; + virtual double dg_de(double seq, double eeq, double t, double T) const; private: double e1_(double seq, double T) const; @@ -333,10 +316,12 @@ static Register regMinCreep225Cr1MoCreep; /// Creep trial state class CreepModelTrialState : public TrialState { public: - virtual ~CreepModelTrialState() {}; + CreepModelTrialState(const Symmetric & s_np1, const Symmetric & e_n, double T, double dt, double t) : + s_np1(s_np1), e_n(e_n), T(T), dt(dt), t(t) + {}; + Symmetric s_np1; + Symmetric e_n; double T, dt, t; - double s_np1[6]; - double e_n[6]; }; /// Interface to creep models @@ -347,34 +332,28 @@ class NEML_EXPORT CreepModel: public NEMLObject, public Solvable { CreepModel(ParameterSet & params); /// Use the creep rate function to update the creep strain - void update(const double * const s_np1, - double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const A_np1); + void update(const Symmetric & s_np1, + Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, + double t_np1, double t_n, + SymSymR4 & A_np1); /// The creep rate as a function of stress, strain, time, and temperature - virtual void f(const double * const s, const double * const e, double t, double T, - double * const f) const = 0; + virtual Symmetric f(const Symmetric & s, const Symmetric & e, double t, double T) const = 0; /// The derivative of the creep rate wrt stress - virtual void df_ds(const double * const s, const double * const e, double t, double T, - double * const df) const = 0; + virtual SymSymR4 df_ds(const Symmetric & s, const Symmetric & e, double t, double T) const = 0; /// The derivative of the creep rate wrt strain - virtual void df_de(const double * const s, const double * const e, double t, double T, - double * const df) const = 0; + virtual SymSymR4 df_de(const Symmetric & s, const Symmetric & e, double t, double T) const = 0; /// The derivative of the creep rate wrt time, defaults to zero - virtual void df_dt(const double * const s, const double * const e, double t, double T, - double * const df) const; + virtual Symmetric df_dt(const Symmetric & s, const Symmetric & e, double t, double T) const; /// The derivative of the creep rate wrt temperature, defaults to zero - virtual void df_dT(const double * const s, const double * const e, double t, double T, - double * const df) const; + virtual Symmetric df_dT(const Symmetric & s, const Symmetric & e, double t, double T) const; /// Setup a trial state for the solver - void make_trial_state(const double * const s_np1, - const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - CreepModelTrialState & ts) const; + std::unique_ptr make_trial_state(const Symmetric & s_np1, + const Symmetric & e_n, + double T_np1, double T_n, + double t_np1, double t_n) const; /// Number of solver parameters virtual size_t nparams() const; @@ -385,8 +364,7 @@ class NEML_EXPORT CreepModel: public NEMLObject, public Solvable { double * const J); private: - void calc_tangent_(const double * const e_np1, CreepModelTrialState & ts, - double * const A_np1); + SymSymR4 calc_tangent_(const Symmetric & e_np1, CreepModelTrialState & ts); protected: const double rtol_, atol_; @@ -409,28 +387,23 @@ class NEML_EXPORT J2CreepModel: public CreepModel { static ParameterSet parameters(); /// creep_rate = dev(s) / ||dev(s)|| * scalar(effective_strain, - /// effective_stress, time, temperature) - virtual void f(const double * const s, const double * const e, double t, double T, - double * const f) const; - /// Derivative of creep rate wrt stress - virtual void df_ds(const double * const s, const double * const e, double t, double T, - double * const df) const; - /// Derivative of creep rate wrt strain - virtual void df_de(const double * const s, const double * const e, double t, double T, - double * const df) const; - /// Derivative of creep rate wrt time - virtual void df_dt(const double * const s, const double * const e, double t, double T, - double * const df) const; - /// Derivative of creep rate wrt temperature - virtual void df_dT(const double * const s, const double * const e, double t, double T, - double * const df) const; + /// The creep rate as a function of stress, strain, time, and temperature + virtual Symmetric f(const Symmetric & s, const Symmetric & e, double t, double T) const; + /// The derivative of the creep rate wrt stress + virtual SymSymR4 df_ds(const Symmetric & s, const Symmetric & e, double t, double T) const; + /// The derivative of the creep rate wrt strain + virtual SymSymR4 df_de(const Symmetric & s, const Symmetric & e, double t, double T) const; + /// The derivative of the creep rate wrt time, defaults to zero + virtual Symmetric df_dt(const Symmetric & s, const Symmetric & e, double t, double T) const; + /// The derivative of the creep rate wrt temperature, defaults to zero + virtual Symmetric df_dT(const Symmetric & s, const Symmetric & e, double t, double T) const; private: // Helpers for computing the above - double seq(const double * const s) const; - double eeq(const double * const e) const; - void sdir(double * const s) const; - void edir(double * const e) const; + double seq(const Symmetric & s) const; + double eeq(const Symmetric & e) const; + Symmetric sdir(const Symmetric & s) const; + Symmetric edir(const Symmetric & e) const; private: std::shared_ptr rule_; diff --git a/include/damage.h b/include/damage.h index 714d28e6..7a7e8de5 100644 --- a/include/damage.h +++ b/include/damage.h @@ -20,27 +20,28 @@ class NEML_EXPORT NEMLDamagedModel_sd: public NEMLModel_sd { /// Input is an elastic model, an undamaged base material, and the CTE NEMLDamagedModel_sd(ParameterSet & params); - /// How many history variables? Equal to base_history + ndamage - virtual size_t nhist() const; + /// Populate the internal variables + virtual void populate_state(History & hist) const; /// Initialize base according to the base model and damage according to - /// init_damage - virtual void init_hist(double * const hist) const; + virtual void init_state(History & hist) const; /// The damaged stress update - virtual void update_sd( - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, - double & u_np1, double u_n, - double & p_np1, double p_n) = 0; + virtual void update_sd_state( + const Symmetric & E_np1, const Symmetric & E_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & S_np1, const Symmetric & S_n, + History & H_np1, const History & H_n, + SymSymR4 & AA_np1, + double & u_np1, double u_n, + double & p_np1, double p_n) = 0; /// Number of damage variables virtual size_t ndamage() const = 0; + /// Populate the damage variables + virtual void populate_damage(History & hist) const = 0; /// Setup the damage variables - virtual void init_damage(double * const damage) const = 0; + virtual void init_damage(History & hist) const = 0; /// Override the elastic model virtual void set_elastic_model(std::shared_ptr emodel); @@ -52,13 +53,20 @@ class NEML_EXPORT NEMLDamagedModel_sd: public NEMLModel_sd { /// Scalar damage trial state class SDTrialState: public TrialState { public: - virtual ~SDTrialState() {}; - double e_np1[6]; - double e_n[6]; - double T_np1, T_n, t_np1, t_n, u_n, p_n; - double s_n[6]; - double w_n; - std::vector h_n; + SDTrialState(const Symmetric & e_np1, const Symmetric & e_n, + const Symmetric & s_n, + double T_np1, double T_n, double t_np1, + double t_n, double u_n, double p_n, double w_n, + const History & h_n) : + e_np1(e_np1), e_n(e_n), s_n(s_n), T_np1(T_np1), T_n(t_n), + t_np1(t_np1), t_n(t_n), u_n(u_n), p_n(p_n), w_n(w_n), + h_n(h_n) + {}; + Symmetric e_np1; + Symmetric e_n; + Symmetric s_n; + double T_np1, T_n, t_np1, t_n, u_n, p_n, w_n; + History h_n; }; /// Special case where the damage variable is a scalar @@ -77,20 +85,22 @@ class NEML_EXPORT NEMLScalarDamagedModel_sd: public NEMLDamagedModel_sd, public static std::unique_ptr initialize(ParameterSet & params); /// Stress update using the scalar damage model - virtual void update_sd( - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, - double & u_np1, double u_n, - double & p_np1, double p_n); + virtual void update_sd_state( + const Symmetric & E_np1, const Symmetric & E_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & S_np1, const Symmetric & S_n, + History & H_np1, const History & H_n, + SymSymR4 & AA_np1, + double & u_np1, double u_n, + double & p_np1, double p_n); /// Equal to 1 virtual size_t ndamage() const; + /// Populate damage + virtual void populate_damage(History & hist) const; /// Initialize to zero - virtual void init_damage(double * const damage) const; + virtual void init_damage(History & hist) const; /// Number of parameters for the solver virtual size_t nparams() const; @@ -100,11 +110,10 @@ class NEML_EXPORT NEMLScalarDamagedModel_sd: public NEMLDamagedModel_sd, public virtual void RJ(const double * const x, TrialState * ts,double * const R, double * const J); /// Setup a trial state from known information - void make_trial_state(const double * const e_np1, const double * const e_n, + SDTrialState make_trial_state(const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, const double * const h_n, - double u_n, double p_n, - SDTrialState & tss); + const Symmetric & s_n, const History & h_n, + double u_n, double p_n); /// Used to find the damage value from the history virtual double get_damage(const double *const h_np1); /// Used to determine if element should be deleted @@ -113,15 +122,14 @@ class NEML_EXPORT NEMLScalarDamagedModel_sd: public NEMLDamagedModel_sd, public virtual bool is_damage_model() const; protected: - void tangent_(const double * const e_np1, const double * const e_n, - const double * const s_np1, const double * const s_n, - double T_np1, double T_n, double t_np1, double t_n, - double w_np1, double w_n, const double * const A_prime, - double * const A); - void ekill_update_(double T_np1, const double * const e_np1, - double * const s_np1, - double * const h_np1, const double * const h_n, - double * A_np1, + SymSymR4 tangent_(const Symmetric & e_np1, const Symmetric & e_n, + const Symmetric & s_np1, const Symmetric & s_n, + double T_np1, double T_n, double t_np1, double t_n, + double w_np1, double w_n, const SymSymR4 & A_prime); + void ekill_update_(double T_np1, const Symmetric & e_np1, + Symmetric & s_np1, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, double & u_np1, double u_n, double & p_np1, double p_n); diff --git a/include/general_flow.h b/include/general_flow.h index e3007058..717bc866 100644 --- a/include/general_flow.h +++ b/include/general_flow.h @@ -12,66 +12,39 @@ namespace neml { /// ABC for a completely general flow rule... -class NEML_EXPORT GeneralFlowRule: public NEMLObject { +class NEML_EXPORT GeneralFlowRule: public HistoryNEMLObject { public: GeneralFlowRule(ParameterSet & params); - /// Number of history variables - virtual size_t nhist() const = 0; - /// Initialize the history at time zero - virtual void init_hist(double * const h) = 0; - /// Stress rate - virtual void s(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const sdot) = 0; + virtual Symmetric s(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) = 0; /// Partial of stress rate wrt stress - virtual void ds_ds(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot) = 0; + virtual SymSymR4 ds_ds(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) = 0; /// Partial of stress rate wrt history - virtual void ds_da(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot) = 0; + virtual History ds_da(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) = 0; /// Partial of stress rate wrt strain rate - virtual void ds_de(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot) = 0; + virtual SymSymR4 ds_de(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) = 0; /// History rate - virtual void a(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const adot) = 0; + virtual History a(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) = 0; /// Partial of history rate wrt stress - virtual void da_ds(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot) = 0; + virtual History da_ds(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) = 0; /// Partial of history rate wrt history - virtual void da_da(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot) = 0; + virtual History da_da(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) = 0; /// Partial of history rate wrt strain rate - virtual void da_de(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot) = 0; + virtual History da_de(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) = 0; /// The implementation needs to define inelastic dissipation - virtual void work_rate(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double & p_rate); - - /// The implementation needs to define elastic strain - virtual void elastic_strains(const double * const s_np1, double T_np1, - double * const e_np1) const = 0; + virtual double work_rate(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Set a new elastic model virtual void set_elastic_model(std::shared_ptr emodel); @@ -94,62 +67,40 @@ class NEML_EXPORT TVPFlowRule : public GeneralFlowRule { /// Initialize from parameter set static ParameterSet parameters(); - /// Number of history variables - virtual size_t nhist() const; + // Setup internal state + virtual void populate_hist(History & h) const; /// Initialize history - virtual void init_hist(double * const h); + virtual void init_hist(History & h) const; /// Stress rate - virtual void s(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const sdot); + virtual Symmetric s(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Partial of stress rate wrt stress - virtual void ds_ds(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot); + virtual SymSymR4 ds_ds(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Partial of stress rate wrt history - virtual void ds_da(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot); + virtual History ds_da(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Partial of stress rate wrt strain rate - virtual void ds_de(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot); + virtual SymSymR4 ds_de(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// History rate - virtual void a(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const adot); + virtual History a(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Partial of history rate wrt stress - virtual void da_ds(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot); + virtual History da_ds(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Partial of history rate wrt history - virtual void da_da(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot); + virtual History da_da(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Partial of history rate wrt strain rate - virtual void da_de(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot); + virtual History da_de(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// The implementation needs to define inelastic dissipation - virtual void work_rate(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double & p_rate); - - /// The implementation needs to define elastic strain - virtual void elastic_strains(const double * const s_np1, double T_np1, - double * const e_np1) const; + virtual double work_rate(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Set a new elastic model virtual void set_elastic_model(std::shared_ptr emodel); diff --git a/include/hardening.h b/include/hardening.h index 9158e3cc..76105d12 100644 --- a/include/hardening.h +++ b/include/hardening.h @@ -3,6 +3,7 @@ #include "interpolate.h" #include "objects.h" +#include "history.h" #include "windows.h" @@ -15,13 +16,10 @@ namespace neml { /// Interface for a generic hardening rule // 1) Take alpha to q // 2) Give the gradient of that function -class NEML_EXPORT HardeningRule: public NEMLObject { +class NEML_EXPORT HardeningRule: public HistoryNEMLObject { public: HardeningRule(ParameterSet & params); - /// The number of history variables - virtual size_t nhist() const = 0; - /// Initialize the history - virtual void init_hist(double * const alpha) const = 0; + /// The map between strain-like and stress-like variables virtual void q(const double * const alpha, double T, double * const qv) const = 0; /// The derivative of the map @@ -32,10 +30,10 @@ class NEML_EXPORT HardeningRule: public NEMLObject { class NEML_EXPORT IsotropicHardeningRule: public HardeningRule { public: IsotropicHardeningRule(ParameterSet & params); - /// Number of strain-like history variable, defaults to 1 - virtual size_t nhist() const; - /// Initialize the history, defaults to initializing one variable to 0.0 - virtual void init_hist(double * const alpha) const; + /// Setup the internal state + virtual void populate_hist(History & h) const; + /// Initialize the history + virtual void init_hist(History & h) const; /// Map between the strain variables and the single isotropic hardening /// parameter virtual void q(const double * const alpha, double T, double * const qv) const = 0; @@ -188,10 +186,10 @@ static Register regCombinedIsotropicHardeningRul class NEML_EXPORT KinematicHardeningRule: public HardeningRule { public: KinematicHardeningRule(ParameterSet & params); - /// Number of history variables (6) - virtual size_t nhist() const; - /// Initialize the 6 backstress components to zero - virtual void init_hist(double * const alpha) const; + /// Setup the internal state + virtual void populate_hist(History & h) const; + /// Initialize the history + virtual void init_hist(History & h) const; /// Map between the backstrain and the backstress virtual void q(const double * const alpha, double T, double * const qv) const = 0; @@ -239,10 +237,10 @@ class NEML_EXPORT CombinedHardeningRule: public HardeningRule { /// Default parameters static ParameterSet parameters(); - /// Sum of the two model nhists - virtual size_t nhist() const; - /// Call init_hist on each model - virtual void init_hist(double * const alpha) const; + /// Setup the internal state + virtual void populate_hist(History & h) const; + /// Initialize the history + virtual void init_hist(History & h) const; /// q[0] = isotropic model, q[1:7] = kinematic model virtual void q(const double * const alpha, double T, double * const qv) const; /// Derivative of the map @@ -256,17 +254,12 @@ class NEML_EXPORT CombinedHardeningRule: public HardeningRule { static Register regCombinedHardeningRule; /// ABC of a non-associative hardening rule -class NEML_EXPORT NonAssociativeHardening: public NEMLObject { +class NEML_EXPORT NonAssociativeHardening: public HistoryNEMLObject { public: NonAssociativeHardening(ParameterSet & params); /// How many stress-like variables virtual size_t ninter() const = 0; // How many "q" variables it spits out - /// How many strain-like variables - virtual size_t nhist() const = 0; // How many internal variables it stores - - /// Initialize the strain-like variables - virtual void init_hist(double * const alpha) const = 0; - + /// Map from strain to stress virtual void q(const double * const alpha, double T, double * const qv) const = 0; /// Derivative of the map @@ -392,11 +385,11 @@ class NEML_EXPORT Chaboche: public NonAssociativeHardening { /// 1 (isotropic) + 6 (backstress) = 7 virtual size_t ninter() const; // How many "q" variables it spits out - /// 1 (isotropic) + n_backstresses * 6 - virtual size_t nhist() const; // How many internal variables it stores - /// Initialize everything to zero - virtual void init_hist(double * const alpha) const; + /// Setup the internal state + virtual void populate_hist(History & h) const; + /// Initialize the history + virtual void init_hist(History & h) const; /// Map the isotropic variable, map the backstresses virtual void q(const double * const alpha, double T, double * const qv) const; @@ -452,7 +445,7 @@ class NEML_EXPORT Chaboche: public NonAssociativeHardening { private: std::shared_ptr iso_; const std::vector> c_; - const int n_; + const size_t n_; std::vector> gmodels_; const std::vector> A_; @@ -481,11 +474,11 @@ class NEML_EXPORT ChabocheVoceRecovery: public NonAssociativeHardening { /// 1 (isotropic) + 6 (backstress) = 7 virtual size_t ninter() const; // How many "q" variables it spits out - /// 1 (isotropic) + n_backstresses * 6 - virtual size_t nhist() const; // How many internal variables it stores - - /// Initialize internal variables - virtual void init_hist(double * const alpha) const; + + /// Setup the internal state + virtual void populate_hist(History & h) const; + /// Initialize the history + virtual void init_hist(History & h) const; /// Map the isotropic variable, map the backstresses virtual void q(const double * const alpha, double T, double * const qv) const; @@ -539,7 +532,7 @@ class NEML_EXPORT ChabocheVoceRecovery: public NonAssociativeHardening { const std::shared_ptr r2_; const std::vector> c_; - const int n_; + const size_t n_; std::vector> gmodels_; const std::vector> A_; diff --git a/include/history.h b/include/history.h index 50daf88b..2465c78d 100644 --- a/include/history.h +++ b/include/history.h @@ -19,7 +19,8 @@ enum StorageType { TYPE_SYMMETRIC = 3, TYPE_SKEW = 4, TYPE_ROT = 5, - TYPE_SYMSYM = 6 + TYPE_SYMSYM = 6, + TYPE_BLANK = 7 }; // Black magic to map a type to the enum @@ -124,6 +125,13 @@ class NEML_EXPORT History { error_if_wrong_type_(name, GetStorageType()); return T(&(storage_[loc_.at(name)])); } + + /// Get a pointer to the raw location of an item + double * get_data(std::string name) + { + error_if_not_exists_(name); + return &(storage_[loc_.at(name)]); + } /// Get the location map const std::unordered_map & get_loc() const {return loc_;}; @@ -150,13 +158,22 @@ class NEML_EXPORT History { /// Actually increase internal storage void increase_store(size_t newsize); + + /// Nice form for scalar multiplication + History & operator*=(const double & scalar); /// Multiply everything by a scalar - void scalar_multiply(double scalar); + History & scalar_multiply(const double & scalar); /// Add another history to this one History & operator+=(const History & other); + /// Negation + History operator-() const; + + /// Subtract another history from this one + History & operator-=(const History & other); + /// Combine another history object through a union History & add_union(const History & other); @@ -213,6 +230,9 @@ class NEML_EXPORT History { /// Quick function to check to see if something is in the vector inline bool contains(std::string name) const { return loc_.find(name) != loc_.end();}; + + /// Premultiply by various objects + History premultiply(const SymSymR4 & T); /// Postmultiply by various objects History postmultiply(const SymSymR4 & T); @@ -259,6 +279,58 @@ inline History History::derivative() const return history_derivative(*this); } +/// Scalar multiplication +History operator*(const double & s, const History & v); + +/// Other scalar multiplication +History operator*(const History & v, const double & s); + +/// History addition +History operator+(const History & a, const History & b); + +/// History subtraction +History operator-(const History & a, const History & b); + +/// NEMLObject that maintains some internal state variables +class NEML_EXPORT HistoryNEMLObject: public NEMLObject { + public: + HistoryNEMLObject(ParameterSet & params); + virtual ~HistoryNEMLObject() {}; + + /// Setup the internal state + virtual void populate_hist(History & h) const = 0; + /// Initialize the history + virtual void init_hist(History & h) const = 0; + /// This should be replaced at some point + virtual size_t nhist() const; + + /// Setup a flat vector history + virtual void init_store(double * const h) const; + /// Now just = nhist + virtual size_t nstore() const; + + /// Set the object prefix + void set_variable_prefix(std::string prefix); + /// Get the prefix + std::string get_variable_prefix() const; + /// Assemble a complete variable name + std::string prefix(std::string basename) const; + /// Assemble a complete derivative name + std::string dprefix(std::string a, std::string b) const; + + /// Quickly setup history + virtual History gather_history_(double * data) const; + virtual History gather_history_(const double * data) const; + virtual History gather_blank_history_() const; + + protected: + virtual void cache_history_(); + + protected: + std::string prefix_; + History stored_hist_; +}; + } // namespace neml #endif // HISTORY_H diff --git a/include/math/tensors.h b/include/math/tensors.h index 8d3461d7..66aafc3d 100644 --- a/include/math/tensors.h +++ b/include/math/tensors.h @@ -247,6 +247,9 @@ class NEML_EXPORT Skew: public Tensor { /// Skew a general tensor Skew(const RankTwo & other); + static Skew zero() { return + Skew(std::vector({0,0,0}));}; + RankTwo to_full() const; Skew opposite() const; @@ -581,6 +584,11 @@ NEML_EXPORT SymSymSymR6 operator/(const SymSymSymR6 & v, double s); NEML_EXPORT SymSymSymR6 operator+(const SymSymSymR6 & a, const SymSymSymR6 & b); NEML_EXPORT SymSymSymR6 operator-(const SymSymSymR6 & a, const SymSymSymR6 & b); +// Complicated objective stress update +Symmetric truesdell_update_sym(const Symmetric & D, const Skew & W, + const Symmetric & cauchy_n, + const Symmetric & dS); + } // namespace neml #endif diff --git a/include/models.h b/include/models.h index dd0a05d8..088e1e40 100644 --- a/include/models.h +++ b/include/models.h @@ -8,6 +8,7 @@ #include "general_flow.h" #include "interpolate.h" #include "creep.h" +#include "history.h" #include "windows.h" @@ -22,20 +23,30 @@ namespace neml { /// NEML material model interface definitions // All material models inherit from this base class. It defines interfaces // and provides the methods for reading in material parameters. -class NEML_EXPORT NEMLModel: public NEMLObject { +class NEML_EXPORT NEMLModel: public HistoryNEMLObject { public: NEMLModel(ParameterSet & params); virtual ~NEMLModel() {}; /// Store model to an XML file virtual void save(std::string file_name, std::string model_name); - - /// Total number of stored internal variables - virtual size_t nstore() const = 0; - /// Initialize the internal variables - virtual void init_store(double * const store) const = 0; - - /// Small strain update interface + + /// Setup the history + virtual void populate_hist(History & history) const; + /// Initialize the history + virtual void init_hist(History & history) const; + + /// Setup the actual evolving state + virtual void populate_state(History & history) const = 0; + /// Initialize the actual evolving state + virtual void init_state(History & history) const = 0; + + /// Setup any static state + virtual void populate_static(History & history) const; + /// Initialize any static state + virtual void init_static(History & history) const; + + /// Raw data small strain update interface virtual void update_sd( const double * const e_np1, const double * const e_n, double T_np1, double T_n, @@ -44,9 +55,20 @@ class NEML_EXPORT NEMLModel: public NEMLObject { double * const h_np1, const double * const h_n, double * const A_np1, double & u_np1, double u_n, - double & p_np1, double p_n) = 0; + double & p_np1, double p_n); - /// Large strain incremental update + /// Small strain update, wrapped objects + virtual void update_sd_interface( + const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & s_np1, Symmetric & s_n, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, + double & u_np1, double u_n, + double & p_np1, double p_n) {}; // Fix after all updated + + /// Raw data large strain incremental update virtual void update_ld_inc( const double * const d_np1, const double * const d_n, const double * const w_np1, const double * const w_n, @@ -56,25 +78,55 @@ class NEML_EXPORT NEMLModel: public NEMLObject { double * const h_np1, const double * const h_n, double * const A_np1, double * const B_np1, double & u_np1, double u_n, - double & p_np1, double p_n) = 0; - - /// Number of internal variables that are true material history - virtual size_t nhist() const = 0; - /// Initialize the history variables - virtual void init_hist(double * const hist) const = 0; + double & p_np1, double p_n); + /// Large strain incremental update, wrapped objects + virtual void update_ld_inc_interface( + const Symmetric & d_np1, const Symmetric & d_n, + const Skew & w_np1, const Skew & w_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, SymSkewR4 & B_np1, + double & u_np1, double u_n, + double & p_np1, double p_n) {}; // Fix after all updated + /// Instantaneous thermal expansion coefficient as a function of temperature virtual double alpha(double T) const = 0; /// Elastic strain for a given stress, temperature, and history state virtual void elastic_strains(const double * const s_np1, double T_np1, const double * const h_np1, - double * const e_np1) const = 0; + double * const e_np1) const; + /// Nice interface for the elastic strain calculation + virtual Symmetric elastic_strains_interface(const Symmetric & s_np1, + double T_np1, const History & h_np1) const; + /// Used to find the damage value from the history virtual double get_damage(const double *const h_np1); /// Used to determine if element should be deleted virtual bool should_del_element(const double *const h_np1); /// Used to determine if this is a damage model virtual bool is_damage_model() const; + + /// Number of actual internal variables + size_t nstate() const; + /// Number of static variables + size_t nstatic() const; + + /// Quickly setup state + History gather_state_(double * data) const; + History gather_state_(const double * data) const; + History gather_blank_state_() const; + + protected: + virtual void cache_history_(); + /// Split internal variables into static and actual parts + std::tuple split_state(const History & h) const; + + protected: + History stored_state_; + History stored_static_; }; /// Large deformation incremental update model @@ -82,38 +134,16 @@ class NEML_EXPORT NEMLModel_ldi: public NEMLModel { public: NEMLModel_ldi(ParameterSet & params); - /// The small strain stress update interface - virtual void update_sd( - const double * const e_np1, const double * const e_n, + /// Small strain update, wrapped objects + virtual void update_sd_interface( + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, + Symmetric & s_np1, Symmetric & s_n, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, double & u_np1, double u_n, double & p_np1, double p_n); - - /// Large strain incremental update - virtual void update_ld_inc( - const double * const d_np1, const double * const d_n, - const double * const w_np1, const double * const w_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, double * const B_np1, - double & u_np1, double u_n, - double & p_np1, double p_n) = 0; - - /// Number of stored variables - virtual size_t nstore() const; - /// Initialize stored variables - virtual void init_store(double * const store) const; - - /// Number of stored variables that are true material history - virtual size_t nhist() const = 0; - /// Initialize the stored history - virtual void init_hist(double * const hist) const = 0; }; /// Small deformation stress update @@ -122,38 +152,44 @@ class NEML_EXPORT NEMLModel_sd: public NEMLModel { /// All small strain models use small strain elasticity and CTE NEMLModel_sd(ParameterSet & params); - /// The small strain stress update interface - virtual void update_sd( - const double * const e_np1, const double * const e_n, + /// Small strain update, wrapped objects + virtual void update_sd_interface( + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, + Symmetric & s_np1, Symmetric & s_n, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, + double & u_np1, double u_n, + double & p_np1, double p_n); + + /// The small strain stress update interface with just the state variables + virtual void update_sd_state( + const Symmetric & E_np1, const Symmetric & E_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & S_np1, const Symmetric & S_n, + History & H_np1, const History & H_n, + SymSymR4 & AA_np1, double & u_np1, double u_n, double & p_np1, double p_n) = 0; /// Large strain incremental update - virtual void update_ld_inc( - const double * const d_np1, const double * const d_n, - const double * const w_np1, const double * const w_n, + virtual void update_ld_inc_interface( + const Symmetric & d_np1, const Symmetric & d_n, + const Skew & w_np1, const Skew & w_n, double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, double * const B_np1, + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, SymSkewR4 & B_np1, double & u_np1, double u_n, double & p_np1, double p_n); - /// Number of stored variables - virtual size_t nstore() const; - /// Initialize stored variables - virtual void init_store(double * const store) const; - - /// Number of stored variables that are true material history - virtual size_t nhist() const = 0; - /// Initialize the stored history - virtual void init_hist(double * const hist) const = 0; + /// Setup any static state + virtual void populate_static(History & history) const; + /// Initialize any static state + virtual void init_static(History & history) const; /// Provide the instantaneous CTE virtual double alpha(double T) const; @@ -161,17 +197,16 @@ class NEML_EXPORT NEMLModel_sd: public NEMLModel { const std::shared_ptr elastic() const; /// Return the elastic strains - virtual void elastic_strains(const double * const s_np1, - double T_np1, const double * const h_np1, - double * const e_np1) const; + virtual Symmetric elastic_strains_interface(const Symmetric & s_np1, + double T_np1, const History & h_np1) const; /// Used to override the linear elastic model to match another object's virtual void set_elastic_model(std::shared_ptr emodel); private: - void calc_tangent_(const double * const D, const double * const W, - const double * const C, const double * const S, - double * const A, double * const B); + void calc_tangent_(const Symmetric & D, const Skew & W, + const SymSymR4 & C, const Symmetric & S, + SymSymR4 & A, SymSkewR4 & B); protected: std::shared_ptr elastic_; @@ -179,7 +214,6 @@ class NEML_EXPORT NEMLModel_sd: public NEMLModel { private: std::shared_ptr alpha_; bool truesdell_; - }; /// Adaptive integration, tangent using the usual trick @@ -188,73 +222,72 @@ class SubstepModel_sd: public NEMLModel_sd, public Solvable { SubstepModel_sd(ParameterSet & params); /// Complete substep update - virtual void update_sd( - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, - double & u_np1, double u_n, - double & p_np1, double p_n); + virtual void update_sd_state( + const Symmetric & E_np1, const Symmetric & E_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & S_np1, const Symmetric & S_n, + History & H_np1, const History & H_n, + SymSymR4 & AA_np1, + double & u_np1, double u_n, + double & p_np1, double p_n); /// Single step update virtual void update_step( - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, + const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n, double * const A, double * const E, double & u_np1, double u_n, double & p_np1, double p_n); /// Setup the trial state - virtual TrialState * setup( - const double * const e_np1, const double * const e_n, + virtual std::unique_ptr setup( + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, - const double * const h_n) = 0; + const Symmetric & s_n, + const History & h_n) = 0; /// Ignore update and take an elastic step virtual bool elastic_step( const TrialState * ts, - const double * const e_np1, const double * const e_n, + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, - const double * const h_n) = 0; + const Symmetric & s_n, + const History & h_n) = 0; /// Interpret the x vector virtual void update_internal( const double * const x, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, + const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n) = 0; + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n) = 0; /// Minus the partial derivative of the residual with respect to the strain virtual void strain_partial( const TrialState * ts, - const double * const e_np1, const double * const e_n, + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_np1, const double * const s_n, - const double * const h_np1, const double * const h_n, - double * const de) = 0; + const Symmetric & s_np1, const Symmetric & s_n, + const History & h_np1, const History & h_n, + double * de) = 0; /// Do the work calculation virtual void work_and_energy( const TrialState * ts, - const double * const e_np1, const double * const e_n, + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, + const Symmetric & s_np1, const Symmetric & s_n, + const History & h_np1, const History & h_n, double & u_np1, double u_n, - double & p_np1, double p_n) = 0; + double & p_np1, double p_n); protected: double rtol_, atol_; @@ -279,19 +312,21 @@ class NEML_EXPORT SmallStrainElasticity: public NEMLModel_sd { static std::unique_ptr initialize(ParameterSet & params); /// Small strain stress update - virtual void update_sd( - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, - double & u_np1, double u_n, - double & p_np1, double p_n); - /// Number of history variables (=0) - virtual size_t nhist() const; + virtual void update_sd_state( + const Symmetric & E_np1, const Symmetric & E_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & S_np1, const Symmetric & S_n, + History & H_np1, const History & H_n, + SymSymR4 & AA_np1, + double & u_np1, double u_n, + double & p_np1, double p_n); + + /// Populate internal variables (none) + virtual void populate_state(History & h) const; + /// Initialize history (none to setup) - virtual void init_hist(double * const hist) const; + virtual void init_state(History & h) const; }; static Register regSmallStrainElasticity; @@ -300,46 +335,67 @@ static Register regSmallStrainElasticity; // Store data the solver needs and can be passed into solution interface class SSPPTrialState : public TrialState { public: - virtual ~SSPPTrialState() {}; - double ys, T; // Yield stress, temperature - double e_np1[6]; // Next strain - double ep_n[6]; // Previous value of plastic strain - double s_tr[6]; // Elastic trial stress - double C[36]; // Stiffness + SSPPTrialState(const Symmetric & e_np1, const Symmetric & ep_n, + const Symmetric & s_tr, const SymSymR4 & C, + double ys, double T) : + e_np1(e_np1), ep_n(ep_n), s_tr(s_tr), C(C), ys(ys), T(T) + {}; + Symmetric e_np1; // Next strain + Symmetric ep_n; // Previous plastic strain + Symmetric s_tr; // Trial stress + SymSymR4 C; // Elastic stiffness + double ys, T; // Yield strength and temperature }; /// Small strain rate independent plasticity trial state class SSRIPTrialState : public TrialState { public: - virtual ~SSRIPTrialState() {}; - double ep_tr[6]; // Trial plastic strain - double s_tr[6]; // Trial stress - double e_np1[6]; // Next strain - double C[36]; // Elastic stiffness - double T; // Temperature - std::vector h_tr; // Trial history + SSRIPTrialState(const Symmetric & e_np1, const Symmetric & ep_tr, + const Symmetric & s_tr, const SymSymR4 & C, + const History & h_tr, double T) : + e_np1(e_np1), ep_tr(ep_tr), s_tr(s_tr), C(C), + h_tr(h_tr), T(T) + {}; + + Symmetric e_np1; // Next strain + Symmetric ep_tr; // Trial plastic strain + Symmetric s_tr; // Trial stress + SymSymR4 C; // Elastic stiffness + History h_tr; // Trial history + double T; // Temperature }; /// Small strain creep+plasticity trial state class SSCPTrialState : public TrialState { public: - virtual ~SSCPTrialState() {}; - double ep_strain[6]; // Current plastic strain - double e_n[6], e_np1[6]; // Previous and next total strain - double s_n[6]; // Previous stress + SSCPTrialState(const Symmetric & ep_strain, const Symmetric & e_n, + const Symmetric & e_np1, const Symmetric & s_n, + double T_n, double T_np1, double t_n, double t_np1, + const History & h_n) : + ep_strain(ep_strain), e_n(e_n), e_np1(e_np1), s_n(s_n), + T_n(T_n), T_np1(T_np1), t_n(t_n), t_np1(t_np1), h_n(h_n) + {}; + Symmetric ep_strain; // Current plastic strain + Symmetric e_n, e_np1; // Previous and next total strain + Symmetric s_n; // Previous stress double T_n, T_np1, t_n, t_np1; // Next and previous time and temperature - std::vector h_n; // Previous history vector + History h_n; // Previous history vector }; /// General inelastic integrator trial state class GITrialState : public TrialState { public: - virtual ~GITrialState() {}; - double e_dot[6]; // Strain rate - double s_n[6]; // Previous stress - double T, Tdot, dt; // Temperature, temperature rate, time inc. - std::vector h_n; // Previous history - double s_guess[6]; // Reasonable guess at the next stress + GITrialState(const Symmetric & e_dot, const Symmetric & s_n, + const Symmetric & s_guess, const History & h_n, + double T, double Tdot, double dt) : + e_dot(e_dot), s_n(s_n), s_guess(s_guess), h_n(h_n), + T(T), Tdot(Tdot), dt(dt) + {}; + Symmetric e_dot; // Strain rate + Symmetric s_n; // Previous stress + Symmetric s_guess; // Guess at next stress + History h_n; // Previous history + double T, Tdot, dt; // Temperature, temperature rate, time increment }; /// Small strain, associative, perfect plasticity @@ -361,11 +417,11 @@ class NEML_EXPORT SmallStrainPerfectPlasticity: public SubstepModel_sd { static ParameterSet parameters(); /// Setup from a ParameterSet static std::unique_ptr initialize(ParameterSet & params); - - /// Number of history variables (=0) - virtual size_t nhist() const; + + /// Populate the internal variables (nothing) + virtual void populate_state(History & h) const; /// Initialize history (nothing to do) - virtual void init_hist(double * const hist) const; + virtual void init_state(History & h) const; /// Number of nonlinear equations to solve in the integration virtual size_t nparams() const; @@ -376,61 +432,44 @@ class NEML_EXPORT SmallStrainPerfectPlasticity: public SubstepModel_sd { double * const J); /// Setup the trial state - virtual TrialState * setup( - const double * const e_np1, const double * const e_n, + virtual std::unique_ptr setup( + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, - const double * const h_n); + const Symmetric & s_n, + const History & h_n); /// Take an elastic step virtual bool elastic_step( const TrialState * ts, - const double * const e_np1, const double * const e_n, + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, - const double * const h_n); + const Symmetric & s_n, + const History & h_n); /// Interpret the x vector virtual void update_internal( const double * const x, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, + const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n); + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n); /// Minus the partial derivative of the residual with respect to the strain virtual void strain_partial( const TrialState * ts, - const double * const e_np1, const double * const e_n, + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_np1, const double * const s_n, - const double * const h_np1, const double * const h_n, + const Symmetric & s_np1, const Symmetric & s_n, + const History & h_np1, const History & h_n, double * de); - /// Do the work calculation - virtual void work_and_energy( - const TrialState * ts, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double & u_np1, double u_n, - double & p_np1, double p_n); - /// Helper to return the yield stress double ys(double T) const; - /// Setup a trial state for the solver from the input information - void make_trial_state(const double * const e_np1, const double * const e_n, - double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, const double * const h_n, - SSPPTrialState & ts); - private: std::shared_ptr surface_; std::shared_ptr ys_; @@ -456,58 +495,47 @@ class NEML_EXPORT SmallStrainRateIndependentPlasticity: public SubstepModel_sd { static ParameterSet parameters(); /// Setup from a ParameterSet static std::unique_ptr initialize(ParameterSet & params); - - /// Number of history variables - virtual size_t nhist() const; + + /// Populate internal variables + virtual void populate_state(History & h) const; /// Initialize history at time zero - virtual void init_hist(double * const hist) const; + virtual void init_state(History & h) const; /// Setup the trial state - virtual TrialState * setup( - const double * const e_np1, const double * const e_n, + virtual std::unique_ptr setup( + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, - const double * const h_n); + const Symmetric & s_n, + const History & h_n); /// Ignore update and take an elastic step virtual bool elastic_step( const TrialState * ts, - const double * const e_np1, const double * const e_n, + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, - const double * const h_n); + const Symmetric & s_n, + const History & h_n); /// Interpret the x vector virtual void update_internal( const double * const x, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, + const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n); + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n); /// Minus the partial derivative of the residual with respect to the strain virtual void strain_partial( const TrialState * ts, - const double * const e_np1, const double * const e_n, + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_np1, const double * const s_n, - const double * const h_np1, const double * const h_n, - double * const de); - - /// Do the work calculation - virtual void work_and_energy( - const TrialState * ts, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double & u_np1, double u_n, - double & p_np1, double p_n); + const Symmetric & s_np1, const Symmetric & s_n, + const History & h_np1, const History & h_n, + double * de); /// Number of solver parameters virtual size_t nparams() const; @@ -521,12 +549,6 @@ class NEML_EXPORT SmallStrainRateIndependentPlasticity: public SubstepModel_sd { /// Return the elastic model for subobjects const std::shared_ptr elastic() const; - /// Setup a trial state - void make_trial_state(const double * const e_np1, const double * const e_n, - double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, const double * const h_n, - SSRIPTrialState & ts); - private: std::shared_ptr flow_; }; @@ -552,20 +574,20 @@ class NEML_EXPORT SmallStrainCreepPlasticity: public NEMLModel_sd, public Solvab static std::unique_ptr initialize(ParameterSet & params); /// Small strain stress update - virtual void update_sd( - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, - double & u_np1, double u_n, - double & p_np1, double p_n); - - /// Number of history variables matches the base model - virtual size_t nhist() const; + virtual void update_sd_state( + const Symmetric & E_np1, const Symmetric & E_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & S_np1, const Symmetric & S_n, + History & H_np1, const History & H_n, + SymSymR4 & AA_np1, + double & u_np1, double u_n, + double & p_np1, double p_n); + + /// Populate list of internal variables + virtual void populate_state(History & hist) const; /// Passes call for initial history to base model - virtual void init_hist(double * const hist) const; + virtual void init_state(History & hist) const; /// The number of parameters in the nonlinear equation virtual size_t nparams() const; @@ -576,17 +598,16 @@ class NEML_EXPORT SmallStrainCreepPlasticity: public NEMLModel_sd, public Solvab double * const J); /// Setup a trial state from known information - void make_trial_state(const double * const e_np1, const double * const e_n, - double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, const double * const h_n, - SSCPTrialState & ts); + std::unique_ptr make_trial_state( + const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, + const Symmetric & s_n, const History & h_n); /// Set a new elastic model virtual void set_elastic_model(std::shared_ptr emodel); private: - void form_tangent_(double * const A, double * const B, - double * const A_np1); + SymSymR4 form_tangent_(const SymSymR4 & A, const SymSymR4 & B); private: std::shared_ptr plastic_; @@ -618,56 +639,56 @@ class NEML_EXPORT GeneralIntegrator: public SubstepModel_sd { static std::unique_ptr initialize(ParameterSet & params); /// Setup the trial state - virtual TrialState * setup( - const double * const e_np1, const double * const e_n, + virtual std::unique_ptr setup( + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, - const double * const h_n); + const Symmetric & s_n, + const History & h_n); /// Take an elastic step virtual bool elastic_step( const TrialState * ts, - const double * const e_np1, const double * const e_n, + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, - const double * const h_n); + const Symmetric & s_n, + const History & h_n); /// Interpret the x vector virtual void update_internal( const double * const x, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, + const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n); + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n); /// Minus the partial derivative of the residual with respect to the strain virtual void strain_partial( const TrialState * ts, - const double * const e_np1, const double * const e_n, + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_np1, const double * const s_n, - const double * const h_np1, const double * const h_n, + const Symmetric & s_np1, const Symmetric & s_n, + const History & h_np1, const History & h_n, double * de); - - /// Do the work calculation + + /// Need special call for dissipation virtual void work_and_energy( const TrialState * ts, - const double * const e_np1, const double * const e_n, + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, + const Symmetric & s_np1, const Symmetric & s_n, + const History & h_np1, const History & h_n, double & u_np1, double u_n, double & p_np1, double p_n); - /// Number of history variables - virtual size_t nhist() const; + /// Populate internal variables + virtual void populate_state(History & hist) const; /// Initialize the history at time zero - virtual void init_hist(double * const hist) const; + virtual void init_state(History & hist) const; /// Number of nonlinear equations virtual size_t nparams() const; @@ -677,12 +698,6 @@ class NEML_EXPORT GeneralIntegrator: public SubstepModel_sd { virtual void RJ(const double * const x, TrialState * ts, double * const R, double * const J); - /// Initialize a trial state - void make_trial_state(const double * const e_np1, const double * const e_n, - double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, const double * const h_n, - GITrialState & ts); - /// Set a new elastic model virtual void set_elastic_model(std::shared_ptr emodel); @@ -724,29 +739,27 @@ class NEML_EXPORT KMRegimeModel: public NEMLModel_sd { static std::unique_ptr initialize(ParameterSet & params); /// The small strain stress update - virtual void update_sd( - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, - double & u_np1, double u_n, - double & p_np1, double p_n); + virtual void update_sd_state( + const Symmetric & E_np1, const Symmetric & E_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & S_np1, const Symmetric & S_n, + History & H_np1, const History & H_n, + SymSymR4 & AA_np1, + double & u_np1, double u_n, + double & p_np1, double p_n); - /// The number of model history variables - virtual size_t nhist() const; + /// Populate internal variables + virtual void populate_state(History & hist) const; /// Initialize history at time zero - virtual void init_hist(double * const hist) const; + virtual void init_state(History & hist) const; /// Set a new elastic model virtual void set_elastic_model(std::shared_ptr emodel); private: - double activation_energy_(const double * const e_np1, - const double * const e_n, - double T_np1, - double t_np1, double t_n); + double activation_energy_(const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double t_np1, double t_n); private: std::vector> models_; @@ -756,4 +769,10 @@ class NEML_EXPORT KMRegimeModel: public NEMLModel_sd { static Register regKMRegimeModel; +/// Useful helper to calculate work and energy with the trapezoid rule +std::tuple trapezoid_energy( + const Symmetric & e_np1, const Symmetric & e_n, + const Symmetric & ep_np1, const Symmetric & ep_n, + const Symmetric & s_np1, const Symmetric & s_n); + } // namespace neml diff --git a/include/ri_flow.h b/include/ri_flow.h index 3121e9d1..42829779 100644 --- a/include/ri_flow.h +++ b/include/ri_flow.h @@ -4,6 +4,7 @@ #include "objects.h" #include "surfaces.h" #include "hardening.h" +#include "history.h" #include "math/nemlmath.h" #include "windows.h" @@ -13,15 +14,10 @@ namespace neml { /// ABC describing rate independent flow -class NEML_EXPORT RateIndependentFlowRule: public NEMLObject { +class NEML_EXPORT RateIndependentFlowRule: public HistoryNEMLObject { public: RateIndependentFlowRule(ParameterSet & params); - - /// Number of history variables - virtual size_t nhist() const = 0; - /// Setup the history at time zero - virtual void init_hist(double * const h) const = 0; - + /// Yield surface virtual void f(const double* const s, const double* const alpha, double T, double & fv) const = 0; @@ -66,10 +62,10 @@ class NEML_EXPORT RateIndependentAssociativeFlow: public RateIndependentFlowRule /// Initialize from a parameter set static ParameterSet parameters(); - /// History size according to the HardeningRule - virtual size_t nhist() const; - /// Initialize history with the HardeningRule - virtual void init_hist(double * const h) const; + /// Setup internal state + virtual void populate_hist(History & h) const; + /// Setup the history at time zero + virtual void init_hist(History & h) const; /// Yield surface virtual void f(const double* const s, const double* const alpha, double T, @@ -127,10 +123,10 @@ class NEML_EXPORT RateIndependentNonAssociativeHardening: public RateIndependent /// Initialize from a parameter set static ParameterSet parameters(); - /// History size according to the HardeningRule - virtual size_t nhist() const; - /// Initialize history with the HardeningRule - virtual void init_hist(double * const h) const; + /// Setup internal state + virtual void populate_hist(History & h) const; + /// Setup the history at time zero + virtual void init_hist(History & h) const; /// Yield surface virtual void f(const double* const s, const double* const alpha, double T, diff --git a/include/visco_flow.h b/include/visco_flow.h index 0c5683eb..d4b80e9c 100644 --- a/include/visco_flow.h +++ b/include/visco_flow.h @@ -6,6 +6,7 @@ #include "surfaces.h" #include "hardening.h" #include "interpolate.h" +#include "history.h" #include "windows.h" @@ -14,15 +15,10 @@ namespace neml { /// ABC describing viscoplastic flow -class NEML_EXPORT ViscoPlasticFlowRule: public NEMLObject { +class NEML_EXPORT ViscoPlasticFlowRule: public HistoryNEMLObject { public: ViscoPlasticFlowRule(ParameterSet & params); - /// Number of history variables - virtual size_t nhist() const = 0; - /// Initialize history at time zero - virtual void init_hist(double * const h) const = 0; - /// Scalar flow rate virtual void y(const double* const s, const double* const alpha, double T, double & yv) const = 0; @@ -114,10 +110,10 @@ class NEML_EXPORT SuperimposedViscoPlasticFlowRule : public ViscoPlasticFlowRule /// Number of individual models being summed size_t nmodels() const; - /// Number of history variables - virtual size_t nhist() const; + /// Populate a blank history object + virtual void populate_hist(History & hist) const; /// Initialize history at time zero - virtual void init_hist(double * const h) const; + virtual void init_hist(History & hist) const; /// Scalar flow rate virtual void y(const double* const s, const double* const alpha, double T, @@ -256,10 +252,10 @@ class NEML_EXPORT PerzynaFlowRule : public ViscoPlasticFlowRule { /// Initialize from parameters static ParameterSet parameters(); - /// Number of history variables - virtual size_t nhist() const; + /// Populate a blank history object + virtual void populate_hist(History & hist) const; /// Initialize history at time zero - virtual void init_hist(double * const h) const; + virtual void init_hist(History & hist) const; /// Scalar strain rate virtual void y(const double* const s, const double* const alpha, double T, @@ -312,10 +308,10 @@ class NEML_EXPORT LinearViscousFlow : public ViscoPlasticFlowRule { /// Initialize from parameters static ParameterSet parameters(); - /// Number of history variables - virtual size_t nhist() const; + /// Populate a blank history object + virtual void populate_hist(History & hist) const; /// Initialize history at time zero - virtual void init_hist(double * const h) const; + virtual void init_hist(History & hist) const; /// Scalar strain rate virtual void y(const double* const s, const double* const alpha, double T, @@ -438,10 +434,10 @@ class NEML_EXPORT ChabocheFlowRule: public ViscoPlasticFlowRule { /// Return default parameters static ParameterSet parameters(); - /// Number of history variables (from the hardening model) - virtual size_t nhist() const; + /// Number of history variables + virtual void populate_hist(History & hist) const; /// Initialize history at time zero - virtual void init_hist(double * const h) const; + virtual void init_hist(History & hist) const; // Scalar inelastic strain rate virtual void y(const double* const s, const double* const alpha, double T, @@ -526,11 +522,10 @@ class NEML_EXPORT YaguchiGr91FlowRule: public ViscoPlasticFlowRule { /// Default parameter set static ParameterSet parameters(); - /// Number of history variables (14) - virtual size_t nhist() const; - /// Initialize history (6 values for X1, 6 values for X2, 1 value for Q and - /// 1 value for sigma_a) - virtual void init_hist(double * const h) const; + /// Number of history variables + virtual void populate_hist(History & hist) const; + /// Initialize history at time zero + virtual void init_hist(History & hist) const; /// Scalar inelastic strain rate virtual void y(const double* const s, const double* const alpha, double T, diff --git a/include/walker.h b/include/walker.h index 510bea5b..48f43328 100644 --- a/include/walker.h +++ b/include/walker.h @@ -28,72 +28,50 @@ class NEML_EXPORT WalkerKremplSwitchRule : public GeneralFlowRule { static std::unique_ptr initialize(ParameterSet & params); /// Initialize from parameter set static ParameterSet parameters(); - - /// Number of history variables - virtual size_t nhist() const; + + /// Setup internal state + virtual void populate_hist(History & hist) const; /// Initialize history - virtual void init_hist(double * const h); + virtual void init_hist(History & hist) const; - /// Stress rate - virtual void s(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const sdot); + /// Stress rate + virtual Symmetric s(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Partial of stress rate wrt stress - virtual void ds_ds(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot); + virtual SymSymR4 ds_ds(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Partial of stress rate wrt history - virtual void ds_da(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot); + virtual History ds_da(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Partial of stress rate wrt strain rate - virtual void ds_de(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot); + virtual SymSymR4 ds_de(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// History rate - virtual void a(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const adot); + virtual History a(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Partial of history rate wrt stress - virtual void da_ds(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot); + virtual History da_ds(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Partial of history rate wrt history - virtual void da_da(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot); + virtual History da_da(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Partial of history rate wrt strain rate - virtual void da_de(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot); + virtual History da_de(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// The implementation needs to define inelastic dissipation - virtual void work_rate(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double & p_rate); - - /// The implementation needs to define elastic strain - virtual void elastic_strains(const double * const s_np1, double T_np1, - double * const e_np1) const; + virtual double work_rate(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot); /// Set a new elastic model virtual void set_elastic_model(std::shared_ptr emodel); /// The kappa function controlling rate sensitivity (public for testing) - void kappa(const double * const edot, double T, double & kap); + double kappa(const Symmetric & edot, double T); /// Derivative of kappa wrt the strain rate (public for testing) - void dkappa(const double * const edot, double T, double * const dkap); + Symmetric dkappa(const Symmetric & edot, double T); /// Override initial guess virtual void override_guess(double * const x); @@ -510,16 +488,6 @@ class NEML_EXPORT WrappedViscoPlasticFlowRule : public ViscoPlasticFlowRule { /// Default constructor sets up the structs for the conversion WrappedViscoPlasticFlowRule(ParameterSet & params); - /// Populate a history object - virtual void populate_hist(History & h) const = 0; - /// Initialize with starting values - virtual void initialize_hist(History & h) const = 0; - - /// Number of history variables (from the hardening model) - virtual size_t nhist() const; - /// Initialize history at time zero - virtual void init_hist(double * const h) const; - /// Scalar inelastic strain rate virtual void y(const double* const s, const double* const alpha, double T, double & yv) const; @@ -660,7 +628,7 @@ class NEML_EXPORT TestFlowRule: public WrappedViscoPlasticFlowRule /// Populate a history object virtual void populate_hist(History & h) const; - virtual void initialize_hist(History & h) const; + virtual void init_hist(History & h) const; // Scalar inelastic strain rate virtual void y(const State & state, double & res) const; @@ -705,7 +673,7 @@ class NEML_EXPORT WalkerFlowRule: public WrappedViscoPlasticFlowRule /// Populate a history object virtual void populate_hist(History & h) const; /// Initialize history with time zero values - virtual void initialize_hist(History & h) const; + virtual void init_hist(History & h) const; // Scalar inelastic strain rate virtual void y(const State & state, double & res) const; diff --git a/neml/__init__.py b/neml/__init__.py index 5fcc9d4c..32fe0805 100644 --- a/neml/__init__.py +++ b/neml/__init__.py @@ -2,3 +2,5 @@ ndir = os.path.dirname(__file__) os.environ['PATH'] += os.pathsep + ndir + +import neml.history diff --git a/src/cp/crystaldamage.cxx b/src/cp/crystaldamage.cxx index 8b2bbce4..b1a7f4d2 100644 --- a/src/cp/crystaldamage.cxx +++ b/src/cp/crystaldamage.cxx @@ -6,7 +6,7 @@ namespace neml { CrystalDamageModel::CrystalDamageModel(ParameterSet & params, std::vector vars) : - NEMLObject(params), + HistoryNEMLObject(params), varnames_(vars) { @@ -27,7 +27,7 @@ void CrystalDamageModel::set_varnames(std::vector names) varnames_ = names; } -void CrystalDamageModel::populate_history(History & history) const +void CrystalDamageModel::populate_hist(History & history) const { for (auto name : varnames_) history.add(name); @@ -56,7 +56,7 @@ ParameterSet NilDamageModel::parameters() return pset; } -void NilDamageModel::init_history(History & history) const +void NilDamageModel::init_hist(History & history) const { history.get("whatever") = 0.0; } @@ -170,7 +170,7 @@ ParameterSet PlanarDamageModel::parameters() return pset; } -void PlanarDamageModel::init_history(History & history) const +void PlanarDamageModel::init_hist(History & history) const { for (auto vn : varnames_) history.get(vn) = damage_->setup(); diff --git a/src/cp/crystaldamage_wrap.cxx b/src/cp/crystaldamage_wrap.cxx index 1e34a997..dfc17bae 100644 --- a/src/cp/crystaldamage_wrap.cxx +++ b/src/cp/crystaldamage_wrap.cxx @@ -11,13 +11,11 @@ namespace neml { PYBIND11_MODULE(crystaldamage, m) { m.doc() = "Crystal plasticity damage models"; - py::class_>(m, "CrystalDamageModel") .def_property_readonly("nvars", &CrystalDamageModel::nvars) .def_property_readonly("varnames", &CrystalDamageModel::varnames) .def("set_varnames", &CrystalDamageModel::set_varnames) - .def("populate_history", &CrystalDamageModel::populate_history) - .def("init_history", &CrystalDamageModel::init_history) .def("projection", &CrystalDamageModel::projection) .def("d_projection_d_stress", &CrystalDamageModel::d_projection_d_stress) .def("d_projection_d_history", &CrystalDamageModel::d_projection_d_history) diff --git a/src/cp/hucocks.cxx b/src/cp/hucocks.cxx index a98c8a88..29c474dc 100644 --- a/src/cp/hucocks.cxx +++ b/src/cp/hucocks.cxx @@ -4,7 +4,7 @@ namespace neml { HuCocksPrecipitationModel::HuCocksPrecipitationModel( ParameterSet & params) : - NEMLObject(params), + HistoryNEMLObject(params), c0_(params.get_object_parameter_vector("c0")), cp_(params.get_object_parameter_vector("cp")), ceq_(params.get_object_parameter_vector("ceq")), @@ -85,13 +85,13 @@ void HuCocksPrecipitationModel::set_varnames(std::vector vars) varnames_ = vars; } -void HuCocksPrecipitationModel::populate_history(History & history) const +void HuCocksPrecipitationModel::populate_hist(History & history) const { for (auto vn : varnames_) history.add(vn); } -void HuCocksPrecipitationModel::init_history(History & history) const +void HuCocksPrecipitationModel::init_hist(History & history) const { history.get(varnames_[0]) = f_init_ / fs_; history.get(varnames_[1]) = r_init_ / rs_; @@ -565,14 +565,14 @@ void DislocationSpacingHardening::set_varnames(std::vector vars) init_cache_(); } -void DislocationSpacingHardening::populate_history(History & history) const +void DislocationSpacingHardening::populate_hist(History & history) const { for (auto vn : varnames_) { history.add(vn); } } -void DislocationSpacingHardening::init_history(History & history) const +void DislocationSpacingHardening::init_hist(History & history) const { for (auto vn : varnames_) { history.get(vn) = L0_; @@ -812,19 +812,19 @@ void HuCocksHardening::set_varnames(std::vector vars) throw std::runtime_error("Cannot override varnames for HuCocksHardening"); } -void HuCocksHardening::populate_history(History & history) const +void HuCocksHardening::populate_hist(History & history) const { - dmodel_->populate_history(history); + dmodel_->populate_hist(history); for (auto pmodel : pmodels_) - pmodel->populate_history(history); + pmodel->populate_hist(history); } -void HuCocksHardening::init_history(History & history) const +void HuCocksHardening::init_hist(History & history) const { history.zero(); - dmodel_->init_history(history); + dmodel_->init_hist(history); for (auto pmodel : pmodels_) - pmodel->init_history(history); + pmodel->init_hist(history); } double HuCocksHardening::hist_to_tau(size_t g, size_t i, @@ -925,7 +925,7 @@ History HuCocksHardening::d_hist_d_s(const Symmetric & stress, // These are zero for (size_t i = 0; i < pmodels_.size(); i++) { History pm; - pmodels_[i]->populate_history(pm); + pmodels_[i]->populate_hist(pm); History zero = pm.derivative().zero(); res.add_union(zero); } @@ -944,7 +944,7 @@ History HuCocksHardening::d_hist_d_h(const Symmetric & stress, std::vector phists; for (auto pmodel : pmodels_) { History pm; - pmodel->populate_history(pm); + pmodel->populate_hist(pm); phists.push_back(pm.zero()); } diff --git a/src/cp/hucocks_wrap.cxx b/src/cp/hucocks_wrap.cxx index 8375ce23..d8f9a454 100644 --- a/src/cp/hucocks_wrap.cxx +++ b/src/cp/hucocks_wrap.cxx @@ -15,7 +15,7 @@ PYBIND11_MODULE(hucocks, m) { m.doc() = "Objects for the Hu & Cocks 316H model"; - py::class_>(m, "HuCocksPrecipitationModel") .def(py::init([](py::args args, py::kwargs kwargs) @@ -26,8 +26,6 @@ PYBIND11_MODULE(hucocks, m) { })) .def("varnames", &HuCocksPrecipitationModel::varnames) .def("set_varnames", &HuCocksPrecipitationModel::set_varnames) - .def("populate_history", &HuCocksPrecipitationModel::populate_history) - .def("init_history", &HuCocksPrecipitationModel::init_history) .def("f", &HuCocksPrecipitationModel::f) .def("r", &HuCocksPrecipitationModel::r) .def("N", &HuCocksPrecipitationModel::N) diff --git a/src/cp/inelasticity.cxx b/src/cp/inelasticity.cxx index 0a27e6c4..3d9137b1 100644 --- a/src/cp/inelasticity.cxx +++ b/src/cp/inelasticity.cxx @@ -5,7 +5,7 @@ namespace neml { InelasticModel::InelasticModel(ParameterSet & params) : - NEMLObject(params) + HistoryNEMLObject(params) { } @@ -43,12 +43,12 @@ std::unique_ptr NoInelasticity::initialize(ParameterSet & params) return neml::make_unique(params); } -void NoInelasticity::populate_history(History & history) const +void NoInelasticity::populate_hist(History & history) const { return; } -void NoInelasticity::init_history(History & history) const +void NoInelasticity::init_hist(History & history) const { return; } @@ -169,14 +169,14 @@ std::unique_ptr AsaroInelasticity::initialize(ParameterSet & params) return neml::make_unique(params); } -void AsaroInelasticity::populate_history(History & history) const +void AsaroInelasticity::populate_hist(History & history) const { - rule_->populate_history(history); + rule_->populate_hist(history); } -void AsaroInelasticity::init_history(History & history) const +void AsaroInelasticity::init_hist(History & history) const { - rule_->init_history(history); + rule_->init_hist(history); } double AsaroInelasticity::strength(const History & history, Lattice & L, @@ -359,12 +359,12 @@ std::unique_ptr PowerLawInelasticity::initialize(ParameterSet & para return neml::make_unique(params); } -void PowerLawInelasticity::populate_history(History & history) const +void PowerLawInelasticity::populate_hist(History & history) const { return; } -void PowerLawInelasticity::init_history(History & history) const +void PowerLawInelasticity::init_hist(History & history) const { return; } @@ -508,18 +508,18 @@ std::unique_ptr CombinedInelasticity::initialize(ParameterSet & para return neml::make_unique(params); } -void CombinedInelasticity::populate_history(History & history) const +void CombinedInelasticity::populate_hist(History & history) const { for (auto model : models_) { - model->populate_history(history); + model->populate_hist(history); } return; } -void CombinedInelasticity::init_history(History & history) const +void CombinedInelasticity::init_hist(History & history) const { for (auto model : models_) { - model->init_history(history); + model->init_hist(history); } return; } diff --git a/src/cp/inelasticity_wrap.cxx b/src/cp/inelasticity_wrap.cxx index 68028ed5..0632fccf 100644 --- a/src/cp/inelasticity_wrap.cxx +++ b/src/cp/inelasticity_wrap.cxx @@ -11,10 +11,8 @@ namespace neml { PYBIND11_MODULE(inelasticity, m) { m.doc() = "Inelastic models for crystal plasticity"; - py::class_>(m, + py::class_>(m, "InelasticModel") - .def("populate_history", &InelasticModel::populate_history) - .def("init_history", &InelasticModel::init_history) .def("strength", &InelasticModel::strength) .def("d_p", &InelasticModel::d_p) .def("d_d_p_d_stress", &InelasticModel::d_d_p_d_stress) diff --git a/src/cp/kinematics.cxx b/src/cp/kinematics.cxx index ca56b845..5e671a97 100644 --- a/src/cp/kinematics.cxx +++ b/src/cp/kinematics.cxx @@ -3,7 +3,7 @@ namespace neml { KinematicModel::KinematicModel(ParameterSet & params) : - NEMLObject(params) + HistoryNEMLObject(params) { } @@ -76,14 +76,14 @@ ParameterSet StandardKinematicModel::parameters() return pset; } -void StandardKinematicModel::populate_history(History & history) const +void StandardKinematicModel::populate_hist(History & history) const { - imodel_->populate_history(history); + imodel_->populate_hist(history); } -void StandardKinematicModel::init_history(History & history) const +void StandardKinematicModel::init_hist(History & history) const { - imodel_->init_history(history); + imodel_->init_hist(history); } double StandardKinematicModel::strength(const History & history, Lattice & L, @@ -311,16 +311,16 @@ ParameterSet DamagedStandardKinematicModel::parameters() return pset; } -void DamagedStandardKinematicModel::populate_history(History & history) const +void DamagedStandardKinematicModel::populate_hist(History & history) const { - imodel_->populate_history(history); - dmodel_->populate_history(history); + imodel_->populate_hist(history); + dmodel_->populate_hist(history); } -void DamagedStandardKinematicModel::init_history(History & history) const +void DamagedStandardKinematicModel::init_hist(History & history) const { - imodel_->init_history(history); - dmodel_->init_history(history); + imodel_->init_hist(history); + dmodel_->init_hist(history); } Symmetric DamagedStandardKinematicModel::stress_rate( @@ -602,7 +602,7 @@ Symmetric DamagedStandardKinematicModel::stress_increment( std::vector DamagedStandardKinematicModel::inames_() const { History ihist; - imodel_->populate_history(ihist); + imodel_->populate_hist(ihist); return ihist.items(); } diff --git a/src/cp/kinematics_wrap.cxx b/src/cp/kinematics_wrap.cxx index cc2d52f3..964ffc23 100644 --- a/src/cp/kinematics_wrap.cxx +++ b/src/cp/kinematics_wrap.cxx @@ -11,10 +11,8 @@ namespace neml { PYBIND11_MODULE(kinematics, m) { m.doc() = "Kinematic models for crystal plasticity"; - py::class_>(m, + py::class_>(m, "KinematicModel") - .def("populate_history", &KinematicModel::populate_history) - .def("init_history", &KinematicModel::init_history) .def("strength", &KinematicModel::strength) diff --git a/src/cp/polycrystal.cxx b/src/cp/polycrystal.cxx index b666d77f..b3b1cafb 100644 --- a/src/cp/polycrystal.cxx +++ b/src/cp/polycrystal.cxx @@ -18,20 +18,29 @@ size_t PolycrystalModel::n() const return q0s_.size(); } -size_t PolycrystalModel::nhist() const +void PolycrystalModel::populate_hist(History & hist) const { - return (model_->nstore() + 6 + 6 + 3) * n(); + for (size_t i = 0; i < n(); i++) { + // TODO: fix this somehow + hist.add("history_"+std::to_string(i), TYPE_BLANK, model_->nstore()); + hist.add("stress_"+std::to_string(i)); + hist.add("deformation_rate_"+std::to_string(i)); + hist.add("vorticity_"+std::to_string(i)); + } } -void PolycrystalModel::init_hist(double * const hist) const +void PolycrystalModel::init_hist(History & hist) const { for (size_t i = 0; i < n(); i++) { - model_->init_store(history(hist, i)); - model_->set_active_orientation(history(hist,i), *q0s_[i]); - - std::fill(stress(hist, i), stress(hist, i) + 6, 0); - std::fill(d(hist, i), d(hist, i) + 6, 0); - std::fill(w(hist, i), w(hist, i) + 3, 0); + History subhist(hist.get_data("history_"+std::to_string(i))); + model_->populate_hist(subhist); + model_->init_hist(subhist); + model_->set_active_orientation(subhist.rawptr(), *q0s_[i]); + + hist.get("stress_"+std::to_string(i)) = Symmetric::zero(); + hist.get("deformation_rate_"+std::to_string(i)) = + Symmetric::zero(); + hist.get("vorticity_"+std::to_string(i)) = Skew::zero(); } } @@ -111,16 +120,6 @@ std::unique_ptr TaylorModel::initialize(ParameterSet & params) return neml::make_unique(params); } -size_t TaylorModel::nstore() const -{ - return nhist(); -} - -void TaylorModel::init_store(double * const store) const -{ - init_hist(store); -} - void TaylorModel::update_ld_inc( const double * const d_np1, const double * const d_n, const double * const w_np1, const double * const w_n, diff --git a/src/cp/postprocessors.cxx b/src/cp/postprocessors.cxx index 643216fa..a0a6894f 100644 --- a/src/cp/postprocessors.cxx +++ b/src/cp/postprocessors.cxx @@ -37,7 +37,7 @@ std::unique_ptr PTRTwinReorientation::initialize( return neml::make_unique(params); } -void PTRTwinReorientation::populate_history(const Lattice & L, +void PTRTwinReorientation::populate_hist(const Lattice & L, History & history) const { size_t j = 0; @@ -51,7 +51,7 @@ void PTRTwinReorientation::populate_history(const Lattice & L, history.add("twinned"); } -void PTRTwinReorientation::init_history(const Lattice & L, +void PTRTwinReorientation::init_hist(const Lattice & L, History & history) const { size_t j = 0; diff --git a/src/cp/postprocessors_wrap.cxx b/src/cp/postprocessors_wrap.cxx index 6f6e673d..34f9c4ce 100644 --- a/src/cp/postprocessors_wrap.cxx +++ b/src/cp/postprocessors_wrap.cxx @@ -12,8 +12,8 @@ PYBIND11_MODULE(postprocessors, m) { m.doc() = "Crystal plasticity postprocessors"; py::class_>(m,"CrystalPostprocessor") - .def("populate_history", &CrystalPostprocessor::populate_history) - .def("init_history", &CrystalPostprocessor::init_history) + .def("populate_history", &CrystalPostprocessor::populate_hist) + .def("init_history", &CrystalPostprocessor::init_hist) .def("act", &CrystalPostprocessor::act) ; diff --git a/src/cp/singlecrystal.cxx b/src/cp/singlecrystal.cxx index d98b82ce..15500a0b 100644 --- a/src/cp/singlecrystal.cxx +++ b/src/cp/singlecrystal.cxx @@ -15,7 +15,6 @@ SingleCrystalModel::SingleCrystalModel(ParameterSet & params) : verbose_(params.get_parameter("verbose")), linesearch_(params.get_parameter("linesearch")), max_divide_(params.get_parameter("max_divide")), - stored_hist_(false), postprocessors_(params.get_object_parameter_vector("postprocessors")), elastic_predictor_(params.get_parameter("elastic_predictor")), fallback_elastic_predictor_(params.get_parameter("fallback_elastic_predictor")), @@ -23,15 +22,7 @@ SingleCrystalModel::SingleCrystalModel(ParameterSet & params) : elastic_predictor_first_step_(params.get_parameter( "elastic_predictor_first_step")) { - populate_history(stored_hist_); - - // Really dumb way to get the names of the parameters that stay fixed during - // the update - // Look to fix this - History h; - populate_static_(h); - static_names_ = h.get_order(); - static_size_ = h.size(); + cache_history_(); } std::string SingleCrystalModel::type() @@ -70,42 +61,46 @@ std::unique_ptr SingleCrystalModel::initialize(ParameterSet & params return neml::make_unique(params); } -void SingleCrystalModel::populate_history(History & history) const +void SingleCrystalModel::populate_state(History & history) const { - populate_static_(history); - - kinematics_->populate_history(history); + kinematics_->populate_hist(history); } -void SingleCrystalModel::populate_static_(History & history) const +void SingleCrystalModel::populate_static(History & history) const { + NEMLModel_ldi::populate_static(history); + history.add("rotation"); history.add("rotation0"); if (use_nye()) { history.add("nye"); } for (auto pp : postprocessors_) - pp->populate_history(*lattice_, history); + pp->populate_hist(*lattice_, history); +} + +void SingleCrystalModel::init_state(History & history) const +{ + kinematics_->init_hist(history); } -void SingleCrystalModel::init_history(History & history) const +void SingleCrystalModel::init_static(History & history) const { + NEMLModel_ldi::init_static(history); + history.get("rotation") = *q0_; history.get("rotation0") = *q0_; if (use_nye()) { history.get("nye") = RankTwo({0,0,0,0,0,0,0,0,0}); } for (auto pp : postprocessors_) - pp->init_history(*lattice_, history); - - kinematics_->init_history(history); + pp->init_hist(*lattice_, history); } double SingleCrystalModel::strength(double * const hist, double T) const { History h_total = gather_history_(hist); - History h = h_total.split(not_updated_()); - History f = h_total.split(not_updated_(), false); + auto [h, f] = split_state(h_total); return kinematics_->strength(h, *lattice_, T, f); } @@ -127,16 +122,16 @@ void SingleCrystalModel::Fe(double * const stress, double * const hist, FE = ((Symmetric::id() + estrain) * RR).inverse(); } -void SingleCrystalModel::update_ld_inc( - const double * const d_np1, const double * const d_n, - const double * const w_np1, const double * const w_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, double * const B_np1, - double & u_np1, double u_n, - double & p_np1, double p_n) +void SingleCrystalModel::update_ld_inc_interface( + const Symmetric & d_np1, const Symmetric & d_n, + const Skew & w_np1, const Skew & w_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, SymSkewR4 & B_np1, + double & u_np1, double u_n, + double & p_np1, double p_n) { // First step if ((t_n == 0.0) && elastic_predictor_first_step_) { @@ -180,52 +175,36 @@ void SingleCrystalModel::update_ld_inc( } void SingleCrystalModel::attempt_update_ld_inc_( - const double * const d_np1, const double * const d_n, - const double * const w_np1, const double * const w_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, double * const B_np1, - double & u_np1, double u_n, - double & p_np1, double p_n, int trial_type) -{ - // Shut up a pointless memory error - std::fill(h_np1, h_np1+nhist(), 0.0); - - // Setup everything in the appropriate wrappers - const Symmetric D_np1(d_np1); - const Skew W_np1(w_np1); - const Symmetric D_n(d_n); - const Skew W_n(w_n); - + const Symmetric & d_np1, const Symmetric & d_n, + const Skew & w_np1, const Skew & w_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, SymSkewR4 & B_np1, + double & u_np1, double u_n, + double & p_np1, double p_n, int trial_type) +{ double dt = t_np1 - t_n; // This is why I shouldn't do that this way Symmetric D; Skew W; if (dt != 0.0) { - D = (D_np1 - D_n) / dt; - W = (W_np1 - W_n) / dt; + D = (d_np1 - d_n) / dt; + W = (w_np1 - w_n) / dt; } - Symmetric S_np1(s_np1); - const Symmetric S_n(s_n); - - History HF_np1 = gather_history_(h_np1); - const History HF_n = gather_history_(h_n); - // There is a subtle race condition if you don't copy the lattice // because that object now caches data Lattice local_lattice = Lattice(*lattice_); // As the update is decoupled, split the histories into hardening/ // orientation groups - Orientation Q_n = HF_n.get("rotation"); + Orientation Q_n = h_n.get("rotation"); - History H_np1 = HF_np1.split(not_updated_()); - History H_n = HF_n.split(not_updated_()); - History F_n = HF_n.split(not_updated_(), false); + auto [H_np1, F_np1] = split_state(h_np1); + auto [H_n, F_n] = split_state(h_n); /* Begin adaptive stepping */ double dT = T_np1 - T_n; @@ -235,39 +214,39 @@ void SingleCrystalModel::attempt_update_ld_inc_( int subdiv = force_divide_; // Use S_np1 and H_np1 to iterate - S_np1.copy_data(S_n.data()); + s_np1.copy_data(s_n.data()); H_np1.copy_data(H_n.rawptr()); while (progress < target) { double step = 1.0 / pow(2, subdiv); // Decouple the updates - History fixed = kinematics_->decouple(S_np1, D, W, Q_n, H_np1, + History fixed = kinematics_->decouple(s_np1, D, W, Q_n, H_np1, local_lattice, T_n + dT * step, F_n); Symmetric strial; if (trial_type == 1) { // Predict the elastic unload - strial = S_n + kinematics_->stress_increment(S_np1, D, W, dt * step, + strial = s_n + kinematics_->stress_increment(s_np1, D, W, dt * step, local_lattice, Q_n, H_np1, T_n+dT*step); } else { - strial = S_n; + strial = s_n; } // Set the trial state SCTrialState trial(D, W, - strial, S_n, H_np1, // Yes, really + strial, s_n, H_np1, // Yes, really Q_n, local_lattice, T_n + dT * step, dt * step, fixed); // Solve the update try { - solve_substep_(&trial, S_np1, H_np1); + solve_substep_(&trial, s_np1, H_np1); } catch (const NEMLError & e) { subdiv++; @@ -299,14 +278,14 @@ void SingleCrystalModel::attempt_update_ld_inc_( // Calc tangent if we're going to be done if (progress == target) { // Tangent - calc_tangents_(S_np1, H_np1, &trial, A_np1, B_np1); + calc_tangents_(s_np1, H_np1, &trial, A_np1.s(), B_np1.s()); // Calculate the new rotation, if requested if (update_rotation_) { - HF_np1.get("rotation") = update_rot_(S_np1, H_np1, &trial); + h_np1.get("rotation") = update_rot_(s_np1, H_np1, &trial); } else { - HF_np1.get("rotation") = Q_n; + h_np1.get("rotation") = Q_n; } } } @@ -318,28 +297,16 @@ void SingleCrystalModel::attempt_update_ld_inc_( } // Calculate the new energy - u_np1 = u_n + calc_energy_inc_(D_np1, D_n, S_np1, S_n); + u_np1 = u_n + calc_energy_inc_(d_np1, d_n, s_np1, s_n); // Calculate the new dissipation - p_np1 = p_n + calc_work_inc_(D_np1, D_n, S_np1, S_n, T_np1, T_n, - HF_np1.get("rotation"), Q_n, + p_np1 = p_n + calc_work_inc_(d_np1, d_n, s_np1, s_n, T_np1, T_n, + h_np1.get("rotation"), Q_n, H_np1, H_n); // Update model based on any post-processors for (auto pp : postprocessors_) - pp->act(*this, local_lattice, T_np1, D, W, HF_np1, HF_n); -} - -size_t SingleCrystalModel::nhist() const -{ - return stored_hist_.size(); -} - -void SingleCrystalModel::init_hist(double * const hist) const -{ - std::fill(hist, hist+nhist(), 0.0); // Shuts it up about initialized memory - History h = gather_history_(hist); - init_history(h); + pp->act(*this, local_lattice, T_np1, D, W, h_np1, h_n); } double SingleCrystalModel::alpha(double T) const @@ -364,7 +331,7 @@ void SingleCrystalModel::elastic_strains( size_t SingleCrystalModel::nparams() const { - return 6 + nhist() - static_size_; + return 6 + nstate(); } void SingleCrystalModel::init_x(double * const x, TrialState * ts) @@ -521,25 +488,6 @@ void SingleCrystalModel::update_nye(double * const hist, } } -History SingleCrystalModel::gather_history_(double * data) const -{ - History h = gather_blank_history_(); - h.set_data(data); - return h; -} - -History SingleCrystalModel::gather_history_(const double * data) const -{ - History h = gather_blank_history_(); - h.set_data(const_cast(data)); - return h; -} - -History SingleCrystalModel::gather_blank_history_() const -{ - return stored_hist_; -} - void SingleCrystalModel::calc_tangents_(Symmetric & S, History & H, SCTrialState * ts, double * const A, double * const B) @@ -765,9 +713,4 @@ void SingleCrystalModel::solve_substep_(SCTrialState * ts, hist.copy_data(&x[6]); } -std::vector SingleCrystalModel::not_updated_() const -{ - return static_names_; -} - } // namespace neml diff --git a/src/cp/singlecrystal_wrap.cxx b/src/cp/singlecrystal_wrap.cxx index 0d0c75a1..3f27f206 100644 --- a/src/cp/singlecrystal_wrap.cxx +++ b/src/cp/singlecrystal_wrap.cxx @@ -27,8 +27,6 @@ PYBIND11_MODULE(singlecrystal, m) { kwargs, {"kinematics", "lattice"}); })) - .def("populate_history", &SingleCrystalModel::populate_history) - .def("init_history", &SingleCrystalModel::init_history) .def("strength", [](SingleCrystalModel & m, py::array_t h, double T) -> double { diff --git a/src/cp/slipharden.cxx b/src/cp/slipharden.cxx index 3e06911e..03f4ad14 100644 --- a/src/cp/slipharden.cxx +++ b/src/cp/slipharden.cxx @@ -5,7 +5,7 @@ namespace neml { SlipHardening::SlipHardening(ParameterSet & params): - NEMLObject(params) + HistoryNEMLObject(params) { } @@ -25,7 +25,7 @@ History SlipHardening::cache(CacheType type) const void SlipHardening::init_cache_() { blank_ = make_unique(); - populate_history(*blank_); + populate_hist(*blank_); blank_->zero(); double_ = make_unique((*blank_).derivative()); @@ -91,11 +91,11 @@ void FixedStrengthHardening::set_varnames(std::vector vars) init_cache_(); } -void FixedStrengthHardening::populate_history(History & history) const +void FixedStrengthHardening::populate_hist(History & history) const { } -void FixedStrengthHardening::init_history(History & history) const +void FixedStrengthHardening::init_hist(History & history) const { } @@ -199,14 +199,14 @@ void VocePerSystemHardening::set_varnames(std::vector vars) init_cache_(); } -void VocePerSystemHardening::populate_history(History & history) const +void VocePerSystemHardening::populate_hist(History & history) const { for (auto vn : varnames_) { history.add(vn); } } -void VocePerSystemHardening::init_history(History & history) const +void VocePerSystemHardening::init_hist(History & history) const { size_t i = 0; for (auto vn : varnames_) { @@ -383,14 +383,14 @@ void FASlipHardening::set_varnames(std::vector vars) init_cache_(); } -void FASlipHardening::populate_history(History & history) const +void FASlipHardening::populate_hist(History & history) const { for (auto vn : varnames_) { history.add(vn); } } -void FASlipHardening::init_history(History & history) const +void FASlipHardening::init_hist(History & history) const { size_t i = 0; for (auto vn : varnames_) { @@ -563,14 +563,14 @@ void GeneralLinearHardening::set_varnames(std::vector vars) init_cache_(); } -void GeneralLinearHardening::populate_history(History & history) const +void GeneralLinearHardening::populate_hist(History & history) const { for (auto vn : varnames_) { history.add(vn); } } -void GeneralLinearHardening::init_history(History & history) const +void GeneralLinearHardening::init_hist(History & history) const { size_t i = 0; for (auto vn : varnames_) { @@ -790,14 +790,14 @@ void SimpleLinearHardening::set_varnames(std::vector vars) init_cache_(); } -void SimpleLinearHardening::populate_history(History & history) const +void SimpleLinearHardening::populate_hist(History & history) const { for (auto vn : varnames_) { history.add(vn); } } -void SimpleLinearHardening::init_history(History & history) const +void SimpleLinearHardening::init_hist(History & history) const { size_t i = 0; for (auto vn : varnames_) { @@ -1006,14 +1006,14 @@ void LANLTiModel::set_varnames(std::vector vars) init_cache_(); } -void LANLTiModel::populate_history(History & history) const +void LANLTiModel::populate_hist(History & history) const { for (auto vn : varnames_) { history.add(vn); } } -void LANLTiModel::init_history(History & history) const +void LANLTiModel::init_hist(History & history) const { for (size_t i = 0; i < size(); i++) { if (i < nslip_()) { @@ -1271,12 +1271,12 @@ void SlipSingleStrengthHardening::set_varnames(std::vector vars) init_cache_(); } -void SlipSingleStrengthHardening::populate_history(History & history) const +void SlipSingleStrengthHardening::populate_hist(History & history) const { history.add(var_name_); } -void SlipSingleStrengthHardening::init_history(History & history) const +void SlipSingleStrengthHardening::init_hist(History & history) const { history.get(var_name_) = init_strength(); } @@ -1429,14 +1429,14 @@ ParameterSet SumSlipSingleStrengthHardening::parameters() return pset; } -void SumSlipSingleStrengthHardening::populate_history(History & history) const +void SumSlipSingleStrengthHardening::populate_hist(History & history) const { for (size_t i = 0; i < nmodels(); i++) { history.add("strength"+std::to_string(i)); } } -void SumSlipSingleStrengthHardening::init_history(History & history) const +void SumSlipSingleStrengthHardening::init_hist(History & history) const { for (size_t i = 0; i < nmodels(); i++) { history.get("strength"+std::to_string(i)) = models_[i]->init_strength(); diff --git a/src/cp/slipharden_wrap.cxx b/src/cp/slipharden_wrap.cxx index 109db0af..b6e1a52d 100644 --- a/src/cp/slipharden_wrap.cxx +++ b/src/cp/slipharden_wrap.cxx @@ -11,11 +11,9 @@ namespace neml { PYBIND11_MODULE(slipharden, m) { m.doc() = "Crystal plasticity slip rate relations"; - py::class_>(m, "SlipHardening") + py::class_>(m, "SlipHardening") .def_property_readonly("varnames", &SlipHardening::varnames) .def("set_varnames", &SlipHardening::set_varnames) - .def("populate_history", &SlipHardening::populate_history) - .def("init_history", &SlipHardening::init_history) .def("hist_to_tau", &SlipHardening::hist_to_tau) .def("d_hist_to_tau", &SlipHardening::d_hist_to_tau) .def("hist", &SlipHardening::hist) diff --git a/src/cp/sliprules.cxx b/src/cp/sliprules.cxx index f901bef5..ada8405a 100644 --- a/src/cp/sliprules.cxx +++ b/src/cp/sliprules.cxx @@ -3,7 +3,7 @@ namespace neml { SlipRule::SlipRule(ParameterSet & params) : - NEMLObject(params) + HistoryNEMLObject(params) { } @@ -87,17 +87,17 @@ size_t SlipMultiStrengthSlipRule::nstrength() const return strengths_.size(); } -void SlipMultiStrengthSlipRule::populate_history(History & history) const +void SlipMultiStrengthSlipRule::populate_hist(History & history) const { for (auto strength : strengths_) { - strength->populate_history(history); + strength->populate_hist(history); } } -void SlipMultiStrengthSlipRule::init_history(History & history) const +void SlipMultiStrengthSlipRule::init_hist(History & history) const { for (auto strength : strengths_) { - strength->init_history(history); + strength->init_hist(history); } } diff --git a/src/cp/sliprules_wrap.cxx b/src/cp/sliprules_wrap.cxx index d5df0e2c..023729ba 100644 --- a/src/cp/sliprules_wrap.cxx +++ b/src/cp/sliprules_wrap.cxx @@ -11,9 +11,7 @@ namespace neml { PYBIND11_MODULE(sliprules, m) { m.doc() = "Crystal plasticity slip rate relations"; - py::class_>(m, "SlipRule") - .def("populate_history", &SlipRule::populate_history) - .def("init_history", &SlipRule::init_history) + py::class_>(m, "SlipRule") .def("strength", &SlipRule::strength) .def("slip", &SlipRule::slip) .def("d_slip_d_s", &SlipRule::d_slip_d_s) diff --git a/src/creep.cxx b/src/creep.cxx index baeccb3e..b0842b58 100644 --- a/src/creep.cxx +++ b/src/creep.cxx @@ -16,18 +16,14 @@ ScalarCreepRule::ScalarCreepRule(ParameterSet & params) : } // Scalar creep default derivatives for time and temperature -void ScalarCreepRule::dg_dt(double seq, double eeq, double t, double T, - double & dg) const +double ScalarCreepRule::dg_dt(double seq, double eeq, double t, double T) const { - dg = 0.0; - + return 0.0; } -void ScalarCreepRule::dg_dT(double seq, double eeq, double t, double T, - double & dg) const +double ScalarCreepRule::dg_dT(double seq, double eeq, double t, double T) const { - dg = 0.0; - + return 0.0; } // Implementation of power law creep @@ -60,21 +56,21 @@ std::unique_ptr PowerLawCreep::initialize(ParameterSet & params) } -void PowerLawCreep::g(double seq, double eeq, double t, double T, double & g) const +double PowerLawCreep::g(double seq, double eeq, double t, double T) const { - g = A_->value(T) * pow(seq, n_->value(T)); + return A_->value(T) * pow(seq, n_->value(T)); } -void PowerLawCreep::dg_ds(double seq, double eeq, double t, double T, double & dg) const +double PowerLawCreep::dg_ds(double seq, double eeq, double t, double T) const { double nv = n_->value(T); - dg = A_->value(T) * nv * pow(seq, nv - 1.0); + return A_->value(T) * nv * pow(seq, nv - 1.0); } -void PowerLawCreep::dg_de(double seq, double eeq, double t, double T, double & dg) const +double PowerLawCreep::dg_de(double seq, double eeq, double t, double T) const { - dg = 0.0; + return 0.0; } double PowerLawCreep::A(double T) const @@ -117,22 +113,22 @@ std::unique_ptr NormalizedPowerLawCreep::initialize(ParameterSet & p } -void NormalizedPowerLawCreep::g(double seq, double eeq, double t, double T, double & g) const +double NormalizedPowerLawCreep::g(double seq, double eeq, double t, double T) const { - g = pow(seq / s0_->value(T), n_->value(T)); + return pow(seq / s0_->value(T), n_->value(T)); } -void NormalizedPowerLawCreep::dg_ds(double seq, double eeq, double t, double T, double & dg) const +double NormalizedPowerLawCreep::dg_ds(double seq, double eeq, double t, double T) const { double nv = n_->value(T); double s0v = s0_->value(T); - dg = nv / s0v * pow(seq / s0v, nv - 1.0); + return nv / s0v * pow(seq / s0v, nv - 1.0); } -void NormalizedPowerLawCreep::dg_de(double seq, double eeq, double t, double T, double & dg) const +double NormalizedPowerLawCreep::dg_de(double seq, double eeq, double t, double T) const { - dg = 0.0; + return 0.0; } // Implementation of the Blackburn minimum creep rate equation @@ -171,39 +167,38 @@ std::unique_ptr BlackburnMinimumCreep::initialize(ParameterSet & par } -void BlackburnMinimumCreep::g(double seq, double eeq, double t, double T, double & g) const +double BlackburnMinimumCreep::g(double seq, double eeq, double t, double T) const { double A = A_->value(T); double n = n_->value(T); double beta = beta_->value(T); - g = A * pow(sinh(beta * seq / n), n) * exp(-Q_ / (R_ * T)); - + return A * pow(sinh(beta * seq / n), n) * exp(-Q_ / (R_ * T)); } -void BlackburnMinimumCreep::dg_ds(double seq, double eeq, double t, double T, double & dg) const +double BlackburnMinimumCreep::dg_ds(double seq, double eeq, double t, double T) const { double A = A_->value(T); double n = n_->value(T); double beta = beta_->value(T); - dg = A * beta * exp(-Q_ / (R_ * T)) * cosh(beta * seq / n) * + return A * beta * exp(-Q_ / (R_ * T)) * cosh(beta * seq / n) * pow(sinh(beta * seq / n), n - 1.0); } -void BlackburnMinimumCreep::dg_de(double seq, double eeq, double t, double T, double & dg) const +double BlackburnMinimumCreep::dg_de(double seq, double eeq, double t, double T) const { - dg = 0.0; + return 0.0; } -void BlackburnMinimumCreep::dg_dT(double seq, double eeq, double t, double T, double & dg) const +double BlackburnMinimumCreep::dg_dT(double seq, double eeq, double t, double T) const { double A = A_->value(T); double n = n_->value(T); double beta = beta_->value(T); - dg = A * pow(sinh(beta * seq / n), n) * exp(-Q_ / (R_ * T)) * Q_ / (R_ * T * T); + return A * pow(sinh(beta * seq / n), n) * exp(-Q_ / (R_ * T)) * Q_ / (R_ * T * T); } // Implementation of the Swindeman minimum creep rate equation @@ -243,27 +238,24 @@ std::unique_ptr SwindemanMinimumCreep::initialize(ParameterSet & par } -void SwindemanMinimumCreep::g(double seq, double eeq, double t, double T, double & g) const +double SwindemanMinimumCreep::g(double seq, double eeq, double t, double T) const { - g = C_ * pow(seq, n_) * exp(V_ * seq) * exp(-Q_/(T+shift_)); - + return C_ * pow(seq, n_) * exp(V_ * seq) * exp(-Q_/(T+shift_)); } -void SwindemanMinimumCreep::dg_ds(double seq, double eeq, double t, double T, double & dg) const +double SwindemanMinimumCreep::dg_ds(double seq, double eeq, double t, double T) const { - - dg = C_ * exp(-Q_/(T+shift_)) * (n_ + seq * V_) * exp(seq * V_) * pow(seq, n_ - 1.0); - + return C_ * exp(-Q_/(T+shift_)) * (n_ + seq * V_) * exp(seq * V_) * pow(seq, n_ - 1.0); } -void SwindemanMinimumCreep::dg_de(double seq, double eeq, double t, double T, double & dg) const +double SwindemanMinimumCreep::dg_de(double seq, double eeq, double t, double T) const { - dg = 0.0; + return 0.0; } -void SwindemanMinimumCreep::dg_dT(double seq, double eeq, double t, double T, double & dg) const +double SwindemanMinimumCreep::dg_dT(double seq, double eeq, double t, double T) const { - dg = C_ * pow(seq, n_) * exp(V_ * seq) * exp(-Q_/(T+shift_)) * Q_ / + return C_ * pow(seq, n_) * exp(V_ * seq) * exp(-Q_/(T+shift_)) * Q_ / ((T+shift_) * (T+shift_)); } @@ -310,31 +302,29 @@ std::unique_ptr RegionKMCreep::initialize(ParameterSet & params) return neml::make_unique(params); } -void RegionKMCreep::g(double seq, double eeq, double t, double T, double & g) const +double RegionKMCreep::g(double seq, double eeq, double t, double T) const { double A, B; select_region_(seq, T, A, B); double G = emodel_->G(T); double C1 = -G * b3_ / (kboltz_*(T+shift_)); - g = eps0_ * exp(C1*B) * pow(seq / G, C1 * A); - + return eps0_ * exp(C1*B) * pow(seq / G, C1 * A); } -void RegionKMCreep::dg_ds(double seq, double eeq, double t, double T, double & dg) const +double RegionKMCreep::dg_ds(double seq, double eeq, double t, double T) const { double A, B; select_region_(seq, T, A, B); double G = emodel_->G(T); double C1 = -G * b3_ / (kboltz_*(T+shift_)); - dg = eps0_ * exp(C1*B) * C1 * A / G * pow(seq / G, C1 * A - 1.0); - + return eps0_ * exp(C1*B) * C1 * A / G * pow(seq / G, C1 * A - 1.0); } -void RegionKMCreep::dg_de(double seq, double eeq, double t, double T, double & dg) const +double RegionKMCreep::dg_de(double seq, double eeq, double t, double T) const { - dg = 0.0; + return 0.0; } void RegionKMCreep::select_region_(double seq, double T, double & Ai, double & Bi) const @@ -398,7 +388,7 @@ std::unique_ptr NortonBaileyCreep::initialize(ParameterSet & params) return neml::make_unique(params); } -void NortonBaileyCreep::g(double seq, double eeq, double t, double T, double & g) const +double NortonBaileyCreep::g(double seq, double eeq, double t, double T) const { double A = A_->value(T); double m = m_->value(T); @@ -412,11 +402,10 @@ void NortonBaileyCreep::g(double seq, double eeq, double t, double T, double & g eeq = std::numeric_limits::epsilon(); } - g = m * pow(A, 1.0 / m) * pow(seq, n / m) * pow(eeq, (m - 1.0) / m); - + return m * pow(A, 1.0 / m) * pow(seq, n / m) * pow(eeq, (m - 1.0) / m); } -void NortonBaileyCreep::dg_ds(double seq, double eeq, double t, double T, double & dg) const +double NortonBaileyCreep::dg_ds(double seq, double eeq, double t, double T) const { double A = A_->value(T); double m = m_->value(T); @@ -430,11 +419,10 @@ void NortonBaileyCreep::dg_ds(double seq, double eeq, double t, double T, double eeq = std::numeric_limits::epsilon(); } - dg = n * pow(A, 1.0 / m) * pow(seq, n / m - 1.0) * pow(eeq, (m - 1.0) / m); - + return n * pow(A, 1.0 / m) * pow(seq, n / m - 1.0) * pow(eeq, (m - 1.0) / m); } -void NortonBaileyCreep::dg_de(double seq, double eeq, double t, double T, double & dg) const +double NortonBaileyCreep::dg_de(double seq, double eeq, double t, double T) const { double A = A_->value(T); double m = m_->value(T); @@ -448,8 +436,7 @@ void NortonBaileyCreep::dg_de(double seq, double eeq, double t, double T, double eeq = std::numeric_limits::epsilon(); } - dg = (m - 1) * pow(A, 1.0 / m) * pow(seq, n / m) * pow(eeq, -1.0 / m); - + return (m - 1) * pow(A, 1.0 / m) * pow(seq, n / m) * pow(eeq, -1.0 / m); } double NortonBaileyCreep::A(double T) const @@ -508,26 +495,23 @@ std::unique_ptr MukherjeeCreep::initialize(ParameterSet & params) return neml::make_unique(params); } -void MukherjeeCreep::g(double seq, double eeq, double t, double T, - double & g) const +double MukherjeeCreep::g(double seq, double eeq, double t, double T) const { double mu = emodel_->G(T); double Dv = D0_ * exp(-Q_ / (R_ * T)); - g = A_ * Dv * mu * b_ / (k_ * T) * pow(seq / mu, n_); + return A_ * Dv * mu * b_ / (k_ * T) * pow(seq / mu, n_); } -void MukherjeeCreep::dg_ds(double seq, double eeq, double t, double T, - double & dg) const +double MukherjeeCreep::dg_ds(double seq, double eeq, double t, double T) const { double mu = emodel_->G(T); double Dv = D0_ * exp(-Q_ / (R_ * T)); - dg = n_ * A_ * Dv * mu * b_ / (k_ * T) * pow(seq / mu, n_ - 1.0) / mu; + return n_ * A_ * Dv * mu * b_ / (k_ * T) * pow(seq / mu, n_ - 1.0) / mu; } -void MukherjeeCreep::dg_de(double seq, double eeq, double t, double T, - double & dg) const +double MukherjeeCreep::dg_de(double seq, double eeq, double t, double T) const { - dg = 0.0; + return 0.0; } double MukherjeeCreep::A() const @@ -591,27 +575,27 @@ ParameterSet GenericCreep::parameters() return pset; } -void GenericCreep::g(double seq, double eeq, double t, double T, double & g) const +double GenericCreep::g(double seq, double eeq, double t, double T) const { - g = exp(cfn_->value(log(seq))); + return exp(cfn_->value(log(seq))); } -void GenericCreep::dg_ds(double seq, double eeq, double t, double T, double & dg) const +double GenericCreep::dg_ds(double seq, double eeq, double t, double T) const { double f = cfn_->value(log(seq)); double df = cfn_->derivative(log(seq)); if (seq > 0.0) { - dg = f * exp(f) * df / seq; + return f * exp(f) * df / seq; } else { - dg = 0.0; + return 0.0; } } -void GenericCreep::dg_de(double seq, double eeq, double t, double T, double & dg) const +double GenericCreep::dg_de(double seq, double eeq, double t, double T) const { - dg = 0.0; + return 0.0; } // Setup for solve @@ -627,54 +611,43 @@ CreepModel::CreepModel(ParameterSet & params) : } // Creep model default derivatives for time and temperature -void CreepModel::df_dt(const double * const s, const double * const e, double t, - double T, double * const df) const +Symmetric CreepModel::df_dt(const Symmetric & s, const Symmetric & e, double t, double T) const { - std::fill(df, df+6, 0.0); - + return Symmetric(); } -void CreepModel::df_dT(const double * const s, const double * const e, double t, - double T, double * const df) const +Symmetric CreepModel::df_dT(const Symmetric & s, const Symmetric & e, double t, double T) const { - std::fill(df, df+6, 0.0); - + return Symmetric(); } // Implementation of creep model update -void CreepModel::update(const double * const s_np1, - double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const A_np1) +void CreepModel::update(const Symmetric & s_np1, + Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, + double t_np1, double t_n, + SymSymR4 & A_np1) { // Setup the trial state - CreepModelTrialState ts; - make_trial_state(s_np1, e_n, T_np1, T_n, t_np1, t_n, ts); + std::unique_ptr ts = make_trial_state(s_np1, e_n, T_np1, T_n, t_np1, t_n); // Solve for the new creep strain std::vector xv(nparams()); double * x = &xv[0]; - solve(this, x, &ts, {rtol_, atol_, miter_, verbose_, linesearch_}); + solve(this, x, ts.get(), {rtol_, atol_, miter_, verbose_, linesearch_}); // Extract - std::copy(x, x+6, e_np1); + std::copy(x, x+6, e_np1.s()); // Get the tangent - calc_tangent_(e_np1, ts, A_np1); + A_np1 = calc_tangent_(e_np1, *ts); } -void CreepModel::make_trial_state(const double * const s_np1, - const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - CreepModelTrialState & ts) const +std::unique_ptr CreepModel::make_trial_state( + const Symmetric & s_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n) const { - ts.T = T_np1; - ts.dt = t_np1 - t_n; - ts.t = t_np1; - std::copy(e_n, e_n+6, ts.e_n); - std::copy(s_np1, s_np1+6, ts.s_np1); + return std::make_unique(s_np1, e_n, T_np1, t_np1 - t_n, t_np1); } // Implement the solve @@ -688,7 +661,7 @@ void CreepModel::init_x(double * const x, TrialState * ts) CreepModelTrialState * tss = static_cast(ts); // Just make it the previous value - std::copy(tss->e_n, tss->e_n+6, x); + std::copy(tss->e_n.data(), tss->e_n.data()+6, x); } void CreepModel::RJ(const double * const x, TrialState * ts, @@ -696,32 +669,28 @@ void CreepModel::RJ(const double * const x, TrialState * ts, { CreepModelTrialState * tss = static_cast(ts); + Symmetric e_np1(x); + Symmetric R1(R); + SymSymR4 J1(J); + // Residual - f(tss->s_np1, x, tss->t, tss->T, R); - for (int i=0; i<6; i++) R[i] = x[i] - tss->e_n[i] - R[i] * tss->dt; + R1 = e_np1 - tss->e_n - f(tss->s_np1, e_np1, tss->t, tss->T) * tss->dt; // Jacobian - df_de(tss->s_np1, x, tss->t, tss->T, J); - for (int i=0; i<36; i++) J[i] = -J[i] * tss->dt; - for (int i=0; i<6; i++) J[CINDEX(i,i,6)] += 1.0; + J1 = SymSymR4::id() - df_de(tss->s_np1, e_np1, tss->t, tss->T) *tss->dt; } // Helper for tangent -void CreepModel::calc_tangent_(const double * const e_np1, - CreepModelTrialState & ts, double * const A_np1) +SymSymR4 CreepModel::calc_tangent_(const Symmetric & e_np1, CreepModelTrialState & ts) { - double R[6]; - double J[36]; - - RJ(e_np1, &ts, R, J); - invert_mat(J, 6); + Symmetric R; + SymSymR4 J; - for (int i=0; i<36; i++) J[i] = J[i] * ts.dt; + RJ(e_np1.data(), &ts, R.s(), J.s()); - double B[36]; - df_ds(ts.s_np1, e_np1, ts.t, ts.T, B); + SymSymR4 B = df_ds(ts.s_np1, e_np1, ts.t, ts.T); - mat_mat(6, 6, 6, J, B, A_np1); + return (J.inverse() * ts.dt).dot(B); } // Implementation of 2.25Cr-1Mo rule @@ -749,41 +718,41 @@ std::unique_ptr MinCreep225Cr1MoCreep::initialize(ParameterSet & par } -void MinCreep225Cr1MoCreep::g(double seq, double eeq, double t, double T, double & g) const +double MinCreep225Cr1MoCreep::g(double seq, double eeq, double t, double T) const { if (seq < 60.0) { - g = e1_(seq, T); + return e1_(seq, T); } else { if (T <= (13.571 * pow(seq, 0.68127) - 1.8 * seq + 710.78)) { - g = e1_(seq, T); + return e1_(seq, T); } else { - g = e2_(seq, T); + return e2_(seq, T); } } } -void MinCreep225Cr1MoCreep::dg_ds(double seq, double eeq, double t, double T, double & dg) const +double MinCreep225Cr1MoCreep::dg_ds(double seq, double eeq, double t, double T) const { if (seq < 60.0) { - dg = de1_(seq, T); + return de1_(seq, T); } else { if (T <= (13.571 * pow(seq, 0.68127) - 1.8 * seq + 710.78)) { - dg = de1_(seq, T); + return de1_(seq, T); } else { - dg = de2_(seq, T); + return de2_(seq, T); } } } -void MinCreep225Cr1MoCreep::dg_de(double seq, double eeq, double t, double T, double & dg) const +double MinCreep225Cr1MoCreep::dg_de(double seq, double eeq, double t, double T) const { - dg = 0.0; + return 0.0; } double MinCreep225Cr1MoCreep::e1_(double seq, double T) const @@ -848,59 +817,28 @@ std::unique_ptr J2CreepModel::initialize(ParameterSet & params) return neml::make_unique(params); } -void J2CreepModel::f(const double * const s, const double * const e, double t, - double T, double * const f) const +Symmetric J2CreepModel::f(const Symmetric & s, const Symmetric & e, double t, double T) const { - // Gather the effective stresses - double se = seq(s); - double ee = eeq(e); - - // Get the direction - std::copy(s, s+6, f); - sdir(f); - - // Get the rate - double rate; - rule_->g(se, ee, t, T, rate); - - // Multiply the two together - for (int i=0; i<6; i++) f[i] *= 3.0/2.0 * rate; - + // Rate * direction + return 3.0/2.0 * sdir(s) * rule_->g(seq(s), eeq(e), t, T); } -void J2CreepModel::df_ds(const double * const s, const double * const e, - double t, double T, double * const df) const +SymSymR4 J2CreepModel::df_ds(const Symmetric & s, const Symmetric & e, double t, double T) const { // Gather the effective stresses double se = seq(s); double ee = eeq(e); // Get the direction - double dir[6]; - std::copy(s, s+6, dir); - sdir(dir); + Symmetric dir = sdir(s); // Get the rate - double rate; - rule_->g(se, ee, t, T, rate); + double rate = rule_->g(se, ee, t, T); // Get the rate derivative - double drate; - rule_->dg_ds(se, ee, t, T, drate); - - // Get our usual funny identity tensor - double ID[36]; - std::fill(ID, ID+36, 0.0); - for (int i=0; i<6; i++) { - ID[CINDEX(i,i,6)] = 1.0; - } - for (int i=0; i<3; i++) { - for (int j=0; j<3; j++) { - ID[CINDEX(i,j,6)] -= 1.0 / 3.0; - } - } - // Stick on one of our 3/2 here - for (int i=0; i<36; i++) ID[i] *= 3.0 / 2.0; + double drate = rule_->dg_ds(se, ee, t, T); + + SymSymR4 ID = SymSymR4::id_dev() * 3.0 / 2.0; // Begin forming outer products // Hack, really should figure out limit se -> 0.0 @@ -908,120 +846,63 @@ void J2CreepModel::df_ds(const double * const s, const double * const e, se = std::numeric_limits::epsilon(); } - double A[36]; - outer_vec(dir, 6, dir, 6, A); - for (int i=0; i<36; i++) A[i] *= 3.0/2.0 * (drate - rate / se); - for (int i=0; i<6; i++) A[CINDEX(i,i,6)] += rate / se; + SymSymR4 A = 3.0/2.0 * douter(dir, dir) * (drate - rate / se) + SymSymR4::id() * rate / se; - // Do the final multiplication - mat_mat(6, 6, 6, A, ID, df); - + return A.dot(ID); } -void J2CreepModel::df_de(const double * const s, const double * const e, double t, double T, - double * const df) const +SymSymR4 J2CreepModel::df_de(const Symmetric & s, const Symmetric & e, double t, double T) const { - // Gather the effective stresses - double se = seq(s); - double ee = eeq(e); - - // Get the stress direction - double s_dir[6]; - std::copy(s, s+6, s_dir); - sdir(s_dir); - - // Get the strain direction - double e_dir[6]; - std::copy(e, e+6, e_dir); - edir(e_dir); - // Get the derivative - double drate; - rule_->dg_de(se, ee, t, T, drate); - - // Tack onto the direction - for (int i=0; i<6; i++) e_dir[i] *= drate; + double drate = rule_->dg_de(seq(s), eeq(e), t, T); - // Form the final outer product - outer_vec(s_dir, 6, e_dir, 6, df); + // Get the stress and strain direction + Symmetric s_dir = sdir(s); + Symmetric e_dir = edir(e) * drate; + return douter(s_dir, e_dir); } -void J2CreepModel::df_dt(const double * const s, const double * const e, - double t, double T, double * const df) const +Symmetric J2CreepModel::df_dt(const Symmetric & s, const Symmetric & e, double t, double T) const { - // Gather the effective quantities - double se = seq(s); - double ee = eeq(e); - - // Get the stress direction - std::copy(s, s+6, df); - sdir(df); - - // Get the derivative - double drate; - rule_->dg_dt(se, ee, t, T, drate); - - // Multiply - for (int i=0; i<6; i++) df[i] *= 3.0/2.0 * drate; - + return 3.0/2.0 * sdir(s) * rule_->dg_dt(seq(s), eeq(e), t, T); } -void J2CreepModel::df_dT(const double * const s, const double * const e, - double t, double T, double * const df) const +Symmetric J2CreepModel::df_dT(const Symmetric & s, const Symmetric & e, double t, double T) const { - // Gather the effective quantities - double se = seq(s); - double ee = eeq(e); - - // Get the stress direction - std::copy(s, s+6, df); - sdir(df); - - // Get the derivative - double drate; - rule_->dg_dT(se, ee, t, T, drate); - - // Multiply - for (int i=0; i<6; i++) df[i] *= 3.0/2.0 * drate; - + return 3.0/2.0 * sdir(s) * rule_->dg_dT(seq(s), eeq(e), t, T); } // Helpers for J2 plasticity -double J2CreepModel::seq(const double * const s) const +double J2CreepModel::seq(const Symmetric & s) const { - double sdev[6]; - std::copy(s, s+6, sdev); - dev_vec(sdev); - - return sqrt(3.0 / 2.0) * norm2_vec(sdev, 6); + return sqrt(3.0/2.0)*s.dev().norm(); } -double J2CreepModel::eeq(const double * const e) const +double J2CreepModel::eeq(const Symmetric & e) const { - return sqrt(2.0 / 3.0) * norm2_vec(e, 6); + return sqrt(2.0 / 3.0) * e.norm(); } -void J2CreepModel::sdir(double * const s) const +Symmetric J2CreepModel::sdir(const Symmetric & s) const { double se = seq(s); if (se < std::numeric_limits::epsilon()) { - std::fill(s, s+6, 0.0); + return Symmetric(); } - else { - dev_vec(s); - for (int i=0; i<6; i++) s[i] /= se; + else { + return s.dev() / se; } } -void J2CreepModel::edir(double * const e) const +Symmetric J2CreepModel::edir(const Symmetric & e) const { double ee = eeq(e); if (ee < std::numeric_limits::epsilon()) { - std::fill(e, e+6, 0.0); + return Symmetric(); } else { - for (int i=0; i<6; i++) e[i] /= ee; + return e / ee; } } diff --git a/src/creep_wrap.cxx b/src/creep_wrap.cxx index c3c6d2ca..e73da5b5 100644 --- a/src/creep_wrap.cxx +++ b/src/creep_wrap.cxx @@ -26,63 +26,25 @@ PYBIND11_MODULE(creep, m) { auto e_np1 = alloc_vec(6); auto A_np1 = alloc_mat(6,6); - m.update(arr2ptr(s_np1), arr2ptr(e_np1), arr2ptr(e_n), T_np1, T_n, t_np1, t_n, arr2ptr(A_np1)); + Symmetric E_np1(arr2ptr(e_np1)); + SymSymR4 AA_np1(arr2ptr(A_np1)); + m.update(Symmetric(arr2ptr(s_np1)), E_np1, Symmetric(arr2ptr(e_n)), T_np1, T_n, t_np1, t_n, AA_np1); + return std::make_tuple(e_np1, A_np1); }, "Update to the next creep strain & tangent derivative.") - .def("f", - [](const CreepModel & m, py::array_t s, py::array_t e, double t, double T) -> py::array_t - { - auto fv = alloc_vec(6); - m.f(arr2ptr(s), arr2ptr(e), t, T, arr2ptr(fv)); - return fv; - }, "Evaluate creep rate.") - - .def("df_ds", - [](const CreepModel & m, py::array_t s, py::array_t e, double t, double T) -> py::array_t - { - auto dfv = alloc_mat(6,6); - m.df_ds(arr2ptr(s), arr2ptr(e), t, T, arr2ptr(dfv)); - return dfv; - }, "Evaluate creep rate derivative wrt stress.") - - .def("df_de", - [](const CreepModel & m, py::array_t s, py::array_t e, double t, double T) -> py::array_t - { - auto dfv = alloc_mat(6,6); - m.df_de(arr2ptr(s), arr2ptr(e), t, T, arr2ptr(dfv)); - return dfv; - }, "Evaluate creep rate derivative wrt strain.") - - .def("df_dt", - [](const CreepModel & m, py::array_t s, py::array_t e, double t, double T) -> py::array_t - { - auto dfv = alloc_vec(6); - m.df_dt(arr2ptr(s), arr2ptr(e), t, T, arr2ptr(dfv)); - return dfv; - }, "Evaluate creep rate derivative wrt time.") - - .def("df_dT", - [](const CreepModel & m, py::array_t s, py::array_t e, double t, double T) -> py::array_t - { - auto dfv = alloc_vec(6); - m.df_dT(arr2ptr(s), arr2ptr(e), t, T, arr2ptr(dfv)); - return dfv; - }, "Evaluate creep rate derivative wrt temperature.") - + .def("f", &CreepModel::f, "Evaluate creep rate.") + .def("df_ds", &CreepModel::df_ds, "Evaluate creep rate derivative wrt stress.") + .def("df_de", &CreepModel::df_de, "Evaluate creep rate derivative wrt strain.") + .def("df_dt", &CreepModel::df_dt, "Evaluate creep rate derivative wrt time.") + .def("df_dT", &CreepModel::df_dT, "Evaluate creep rate derivative wrt temperature.") .def("make_trial_state", [](CreepModel & m, py::array_t s_np1, py::array_t e_n, double T_np1, double T_n, double t_np1, double t_n) -> std::unique_ptr { - std::unique_ptr ts(new CreepModelTrialState); - m.make_trial_state(arr2ptr(s_np1), - arr2ptr(e_n), - T_np1, T_n, t_np1, t_n, *ts); - - return ts; - + return m.make_trial_state(Symmetric(arr2ptr(s_np1)), Symmetric(arr2ptr(e_n)), T_np1, T_n, t_np1, t_n); }, "Setup trial state for solve") ; @@ -94,45 +56,11 @@ PYBIND11_MODULE(creep, m) { ; py::class_>(m, "ScalarCreepRule") - .def("g", - [](const ScalarCreepRule & m, double seq, double eeq, double t, double T) -> double - { - double gv; - m.g(seq, eeq, t, T, gv); - return gv; - }, "Evaluate creep rate.") - - .def("dg_ds", - [](const ScalarCreepRule & m, double seq, double eeq, double t, double T) -> double - { - double gv; - m.dg_ds(seq, eeq, t, T, gv); - return gv; - }, "Evaluate creep rate derivative wrt stress.") - - .def("dg_de", - [](const ScalarCreepRule & m, double seq, double eeq, double t, double T) -> double - { - double gv; - m.dg_de(seq, eeq, t, T, gv); - return gv; - }, "Evaluate creep rate derivative wrt strain.") - - .def("dg_dt", - [](const ScalarCreepRule & m, double seq, double eeq, double t, double T) -> double - { - double gv; - m.dg_dt(seq, eeq, t, T, gv); - return gv; - }, "Evaluate creep rate wrt time.") - - .def("dg_dT", - [](const ScalarCreepRule & m, double seq, double eeq, double t, double T) -> double - { - double gv; - m.dg_dT(seq, eeq, t, T, gv); - return gv; - }, "Evaluate creep rate wrt temperature.") + .def("g", &ScalarCreepRule::g, "Evaluate the creep rate") + .def("dg_ds", &ScalarCreepRule::dg_ds, "Evaluate creep rate derivative wrt stress.") + .def("dg_de", &ScalarCreepRule::dg_de, "Evaluate creep rate derivative wrt strain.") + .def("dg_dt", &ScalarCreepRule::dg_dt, "Evaluate creep rate derivative wrt time.") + .def("dg_dT", &ScalarCreepRule::dg_dT, "Evaluate creep rate derivative wrt temperature.") ; py::class_>(m, "PowerLawCreep") diff --git a/src/damage.cxx b/src/damage.cxx index 68c0821c..2048fe7a 100644 --- a/src/damage.cxx +++ b/src/damage.cxx @@ -13,15 +13,17 @@ NEMLDamagedModel_sd::NEMLDamagedModel_sd(ParameterSet & params) : } -size_t NEMLDamagedModel_sd::nhist() const +void NEMLDamagedModel_sd::populate_state(History & hist) const { - return ndamage() + base_->nhist(); + populate_damage(hist); + base_->set_variable_prefix(get_variable_prefix()); + base_->populate_state(hist); } -void NEMLDamagedModel_sd::init_hist(double * const hist) const +void NEMLDamagedModel_sd::init_state(History & hist) const { init_damage(hist); - base_->init_hist(&hist[ndamage()]); + base_->init_state(hist); } void NEMLDamagedModel_sd::set_elastic_model(std::shared_ptr @@ -43,6 +45,7 @@ NEMLScalarDamagedModel_sd::NEMLScalarDamagedModel_sd(ParameterSet & params) : dkill_(params.get_parameter("dkill")), sfact_(params.get_parameter("sfact")) { + cache_history_(); } std::string NEMLScalarDamagedModel_sd::type() @@ -79,24 +82,24 @@ std::unique_ptr NEMLScalarDamagedModel_sd::initialize(ParameterSet & return neml::make_unique(params); } -void NEMLScalarDamagedModel_sd::update_sd( - const double * const e_np1, const double * const e_n, +void NEMLScalarDamagedModel_sd::update_sd_state( + const Symmetric & E_np1, const Symmetric & E_n, double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, + Symmetric & S_np1, const Symmetric & S_n, + History & H_np1, const History & H_n, + SymSymR4 & AA_np1, double & u_np1, double u_n, double & p_np1, double p_n) { - if (ekill_ and (h_n[0] >= dkill_)) { - ekill_update_(T_np1, e_np1, s_np1, h_np1, h_n, A_np1, u_np1, u_n, p_np1, p_n); + // Check is this is dead + if (ekill_ and (H_n.get(prefix("damage")) >= dkill_)) { + ekill_update_(T_np1, E_np1, S_np1, H_np1, H_n, AA_np1, u_np1, u_n, p_np1, p_n); return; } // Make trial state - SDTrialState tss; - make_trial_state(e_np1, e_n, T_np1, T_n, t_np1, t_n, s_n, h_n, u_n, p_n, tss); + SDTrialState tss = make_trial_state(E_np1, E_n, T_np1, T_n, t_np1, t_n, S_n, H_n, u_n, p_n); // Call solve std::vector xv(nparams()); @@ -104,30 +107,33 @@ void NEMLScalarDamagedModel_sd::update_sd( solve(this, x, &tss, {rtol_, atol_, miter_, verbose_, linesearch_}); // Do actual stress update - double s_prime_np1[6]; - double s_prime_n[6]; - double A_prime_np1[36]; - std::copy(s_n, s_n+6, s_prime_n); - for (int i=0; i<6; i++) s_prime_n[i] /= (1-h_n[0]); - - base_->update_sd(e_np1, e_n, T_np1, T_n, - t_np1, t_n, s_prime_np1, s_prime_n, - &h_np1[1], &h_n[1], - A_prime_np1, u_np1, u_n, p_np1, p_n); - - - for (int i=0; i<6; i++) s_np1[i] = (1-x[6]) * s_prime_np1[i]; - h_np1[0] = x[6]; + Symmetric S_prime_np1; + Symmetric S_prime_n = S_n / (1-H_n.get(prefix("damage"))); + SymSymR4 A_prime_np1; + + // Split the history + History base_np1 = H_np1.split({prefix("damage")}); + History base_n = H_n.split({prefix("damage")}); - if (ekill_ and (h_np1[0] >= dkill_)) { - ekill_update_(T_np1, e_np1, s_np1, h_np1, h_n, A_np1, u_np1, u_n, p_np1, p_n); + base_->update_sd_state(E_np1, E_n, T_np1, T_n, + t_np1, t_n, S_prime_np1, S_prime_n, + base_np1, base_n, + A_prime_np1, u_np1, u_n, p_np1, p_n); + + // Fix up stress and store damage + double w = x[6]; + S_np1 = (1-w) * S_prime_np1; + H_np1.get(prefix("damage")) = w; + + // Check for death + if (ekill_ and (H_np1.get(prefix("damage")) >= dkill_)) { + ekill_update_(T_np1, E_np1, S_np1, H_np1, H_n, AA_np1, u_np1, u_n, p_np1, p_n); return; } // Create the tangent - tangent_(e_np1, e_n, s_np1, s_n, - T_np1, T_n, t_np1, t_n, - x[6], h_n[0], A_prime_np1, A_np1); + AA_np1 = tangent_(E_np1, E_n, S_np1, S_n, T_np1, T_n, t_np1, t_n, + w, H_n.get(prefix("damage")), A_prime_np1); } size_t NEMLScalarDamagedModel_sd::ndamage() const @@ -135,9 +141,14 @@ size_t NEMLScalarDamagedModel_sd::ndamage() const return 1; } -void NEMLScalarDamagedModel_sd::init_damage(double * const damage) const +void NEMLScalarDamagedModel_sd::populate_damage(History & hist) const { - damage[0] = dmodel_->d_init(); + hist.add(prefix("damage")); +} + +void NEMLScalarDamagedModel_sd::init_damage(History & hist) const +{ + hist.get(prefix("damage")) = dmodel_->d_init(); } size_t NEMLScalarDamagedModel_sd::nparams() const @@ -148,7 +159,7 @@ size_t NEMLScalarDamagedModel_sd::nparams() const void NEMLScalarDamagedModel_sd::init_x(double * const x, TrialState * ts) { SDTrialState * tss = static_cast(ts); - std::copy(tss->s_n, tss->s_n+6, x); + std::copy(tss->s_n.data(), tss->s_n.data()+6, x); // This provides a way for a particular model give a better guess at // the initial damage for the first step. Some models can be singular // for w = 0 @@ -164,31 +175,29 @@ void NEMLScalarDamagedModel_sd::RJ(const double * const x, TrialState * ts, double * const R, double * const J) { SDTrialState * tss = static_cast(ts); - const double * s_curr = x; + Symmetric s_curr(x); double w_curr = x[6]; - double s_prime_curr[6]; - for (int i=0; i<6; i++) s_prime_curr[i] = s_curr[i] / (1-w_curr); - - double s_prime_np1[6]; - double s_prime_n[6]; - double A_prime_np1[36]; - std::vector h_np1_v(base_->nhist()); - double * h_np1 = &h_np1_v[0]; + Symmetric s_prime_curr = s_curr / (1-w_curr); + + Symmetric s_prime_np1; + Symmetric s_prime_n = tss->s_n / (1-tss->w_n); + SymSymR4 A_prime_np1; + + History h_np1 = base_->gather_blank_state_(); double u_np1; double p_np1; - std::copy(tss->s_n, tss->s_n+6, s_prime_n); - for (int i=0; i<6; i++) s_prime_n[i] /= (1-tss->w_n); - - base_->update_sd(tss->e_np1, tss->e_n, tss->T_np1, tss->T_n, + base_->update_sd_state(tss->e_np1, tss->e_n, tss->T_np1, tss->T_n, tss->t_np1, tss->t_n, s_prime_np1, s_prime_n, - h_np1, &tss->h_n[0], + h_np1, tss->h_n, A_prime_np1, u_np1, tss->u_n, p_np1, tss->p_n); - for (int i=0; i<6; i++) R[i] = s_curr[i] - (1-w_curr) * s_prime_np1[i]; + // Through the 6th component + Symmetric Rv(R); + Rv = s_curr - (1-w_curr) * s_prime_np1; double w_np1; - dmodel_->damage(w_curr, tss->w_n, tss->e_np1, tss->e_n, s_prime_curr, s_prime_n, + dmodel_->damage(w_curr, tss->w_n, tss->e_np1.data(), tss->e_n.data(), s_prime_curr.data(), s_prime_n.data(), tss->T_np1, tss->T_n, tss->t_np1, tss->t_n, &w_np1); R[6] = w_curr - w_np1; @@ -197,98 +206,80 @@ void NEMLScalarDamagedModel_sd::RJ(const double * const x, TrialState * ts, J[CINDEX(i,i,7)] = 1.0; } for (int i=0; i<6; i++) { - J[CINDEX(i,6,7)] = s_prime_np1[i]; + J[CINDEX(i,6,7)] = s_prime_np1(i); } - double ws[6]; - dmodel_->ddamage_ds(w_curr, tss->w_n, tss->e_np1, tss->e_n, s_prime_curr, s_prime_n, + Symmetric ws;; + dmodel_->ddamage_ds(w_curr, tss->w_n, tss->e_np1.data(), tss->e_n.data(), s_prime_curr.data(), s_prime_n.data(), tss->T_np1, tss->T_n, - tss->t_np1, tss->t_n, ws); + tss->t_np1, tss->t_n, ws.s()); for (int i=0; i<6; i++) { - J[CINDEX(6,i,7)] = -ws[i] / (1 - w_curr); + J[CINDEX(6,i,7)] = -ws(i) / (1 - w_curr); } double ww; - dmodel_->ddamage_dd(w_curr, tss->w_n, tss->e_np1, tss->e_n, s_prime_curr, s_prime_n, + dmodel_->ddamage_dd(w_curr, tss->w_n, tss->e_np1.data(), tss->e_n.data(), s_prime_curr.data(), s_prime_n.data(), tss->T_np1, tss->T_n, tss->t_np1, tss->t_n, &ww); - J[CINDEX(6,6,7)] = 1.0 - ww - dot_vec(ws, s_curr, 6) / pow(1-w_curr,2.0); + J[CINDEX(6,6,7)] = 1.0 - ww - ws.contract(s_curr) / pow(1-w_curr,2.0); } -void NEMLScalarDamagedModel_sd::make_trial_state( - const double * const e_np1, const double * const e_n, +SDTrialState NEMLScalarDamagedModel_sd::make_trial_state( + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, const double * const h_n, - double u_n, double p_n, - SDTrialState & tss) -{ - std::copy(e_np1, e_np1+6, tss.e_np1); - std::copy(e_n, e_n+6, tss.e_n); - tss.T_np1 = T_np1; - tss.T_n = T_n; - tss.t_np1 = t_np1; - tss.t_n = t_n; - std::copy(s_n, s_n+6, tss.s_n); - tss.h_n.resize(base_->nhist()); - std::copy(h_n+1, h_n+base_->nhist()+1, tss.h_n.begin()); - tss.u_n = u_n; - tss.p_n = p_n; - tss.w_n = h_n[0]; -} - -void NEMLScalarDamagedModel_sd::tangent_( - const double * const e_np1, const double * const e_n, - const double * const s_np1, const double * const s_n, + const Symmetric & s_n, const History & h_n, + double u_n, double p_n) +{ + History base_n = h_n.split({prefix("damage")}); + return SDTrialState(e_np1, e_n, s_n, + T_np1, T_n, t_np1, t_n, + u_n, p_n, h_n.get(prefix("damage")), + base_n); +} + +SymSymR4 NEMLScalarDamagedModel_sd::tangent_( + const Symmetric & e_np1, const Symmetric & e_n, + const Symmetric & s_np1, const Symmetric & s_n, double T_np1, double T_n, double t_np1, double t_n, - double w_np1, double w_n, const double * const A_prime, - double * const A) -{ - double s_prime_np1[6]; - for (int i=0; i<6; i++) s_prime_np1[i] = s_np1[i] / (1.0 - w_np1); - double s_prime_n[6]; - for (int i=0; i<6; i++) s_prime_n[i] = s_n[i] / (1.0 - w_n); - - double dw_ds[6]; - dmodel_->ddamage_ds(w_np1, w_n, e_np1, e_n, s_prime_np1, s_prime_n, T_np1, T_n, - t_np1, t_n, dw_ds); - double dw_de[6]; - dmodel_->ddamage_de(w_np1, w_n, e_np1, e_n, s_prime_np1, s_prime_n, T_np1, T_n, - t_np1, t_n, dw_de); + double w_np1, double w_n, const SymSymR4 & A_prime) +{ + // Just collecting pieces + Symmetric s_prime_np1 = s_np1 / (1.0 - w_np1); + Symmetric s_prime_n = s_n / (1.0 - w_n); + + Symmetric dw_ds; + dmodel_->ddamage_ds(w_np1, w_n, e_np1.data(), e_n.data(), s_prime_np1.data(), s_prime_n.data(), T_np1, T_n, + t_np1, t_n, dw_ds.s()); + Symmetric dw_de; + dmodel_->ddamage_de(w_np1, w_n, e_np1.data(), e_n.data(), s_prime_np1.data(), s_prime_n.data(), T_np1, T_n, + t_np1, t_n, dw_de.s()); double dw_dw; - dmodel_->ddamage_dd(w_np1, w_n, e_np1, e_n, s_prime_np1, s_prime_n, T_np1, T_n, + dmodel_->ddamage_dd(w_np1, w_n, e_np1.data(), e_n.data(), s_prime_np1.data(), s_prime_n.data(), T_np1, T_n, t_np1, t_n, &dw_dw); - double k1 = 1.0 - 1.0 / (1.0 - w_np1) * dot_vec(dw_ds, s_prime_np1, 6) - dw_dw; - double B[36]; - std::fill(B, B+36, 0); - for (int i=0; i<6; i++) B[CINDEX(i,i,6)] = 1.0; - for (int i=0; i<6; i++) dw_ds[i] /= (k1 * (1.0 - w_np1)); - outer_update(s_prime_np1, 6, dw_ds, 6, B); - invert_mat(B, 6); - - double C[36]; - std::copy(A_prime, A_prime+36, C); - for (int i=0; i<36; i++) C[i] *= (1 - w_np1); - for (int i=0; i<6; i++) dw_de[i] /= k1; - outer_update_minus(s_prime_np1, 6, dw_de, 6, C); - mat_mat(6, 6, 6, B, C, A); -} - -void NEMLScalarDamagedModel_sd::ekill_update_(double T_np1, - const double * const e_np1, - double * const s_np1, - double * const h_np1, - const double * const h_n, - double * const A_np1, - double & u_np1, double u_n, - double & p_np1, double p_n) -{ - std::copy(h_n, h_n + nhist(), h_np1); - h_np1[0] = 1.0; - elastic_->C(T_np1, A_np1); - for (int i=0; i<36; i++) A_np1[i] /= sfact_; - mat_vec(A_np1, 6, e_np1, 6, s_np1); + // Actual tensor math + double k1 = 1.0 - 1.0 / (1.0 - w_np1) * dw_ds.contract(s_prime_np1) - dw_dw; + dw_ds /= (k1 * (1.0 - w_np1)); + SymSymR4 B = (SymSymR4::id() + douter(s_prime_np1, dw_ds)).inverse(); + + dw_de /= k1; + SymSymR4 C = A_prime * (1-w_np1) - douter(s_prime_np1, dw_de); + + return B.dot(C); +} + +void NEMLScalarDamagedModel_sd::ekill_update_( + double T_np1, const Symmetric & e_np1, Symmetric & s_np1, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, + double & u_np1, double u_n, + double & p_np1, double p_n) +{ + h_np1.copy_data(h_n.rawptr()); + h_np1.get(prefix("damage")) = 1.0; + A_np1 = elastic_->C(T_np1) / sfact_; + s_np1 = A_np1.dot(e_np1); if (u_n > 0.0) { p_np1 = p_n + u_n; u_np1 = 0.0; @@ -298,13 +289,22 @@ void NEMLScalarDamagedModel_sd::ekill_update_(double T_np1, u_np1 = u_n; } } -double NEMLScalarDamagedModel_sd::get_damage(const double *const h_np1) { - return h_np1[0]; +double NEMLScalarDamagedModel_sd::get_damage(const double *const h_np1) +{ + History h = gather_history_(h_np1); + return h.get(prefix("damage")); +} + +bool NEMLScalarDamagedModel_sd::should_del_element(const double *const h_np1) +{ + History h = gather_history_(h_np1); + return h.get(prefix("damage")) > dkill_; } -bool NEMLScalarDamagedModel_sd::should_del_element(const double *const h_np1) { - return get_damage(h_np1) > dkill_; + +bool NEMLScalarDamagedModel_sd::is_damage_model() const +{ + return true; } -bool NEMLScalarDamagedModel_sd::is_damage_model() const { return true; } ScalarDamage::ScalarDamage(ParameterSet & params) : NEMLObject(params), diff --git a/src/damage_wrap.cxx b/src/damage_wrap.cxx index 5ecb1158..1f913655 100644 --- a/src/damage_wrap.cxx +++ b/src/damage_wrap.cxx @@ -21,13 +21,8 @@ PYBIND11_MODULE(damage, m) { py::class_>(m, "NEMLDamagedModel_sd") .def_property_readonly("ndamage", &NEMLDamagedModel_sd::ndamage, "Number of damage variables.") - .def("init_damage", - [](NEMLDamagedModel_sd & m) -> py::array_t - { - auto h = alloc_vec(m.ndamage()); - m.init_damage(arr2ptr(h)); - return h; - }, "Initialize damage variables.") + .def("init_damage", &NEMLDamagedModel_sd::init_damage) + .def("populate_damage", &NEMLDamagedModel_sd::populate_damage) ; py::class_(m, "SDTrialState") @@ -42,17 +37,15 @@ PYBIND11_MODULE(damage, m) { "damage"}); })) .def("make_trial_state", - [](NEMLScalarDamagedModel_sd & m, py::array_t e_np1, py::array_t e_n, double T_np1, double T_n, double t_np1, double t_n, py::array_t s_n, py::array_t h_n, double u_n, double p_n) -> std::unique_ptr + [](NEMLScalarDamagedModel_sd & m, py::array_t e_np1, py::array_t e_n, double T_np1, double T_n, double t_np1, double t_n, py::array_t s_n, py::array_t h_n, double u_n, double p_n) -> SDTrialState { - std::unique_ptr ts(new SDTrialState); - m.make_trial_state(arr2ptr(e_np1), - arr2ptr(e_n), + History test = m.gather_state_(arr2ptr(h_n)); + return m.make_trial_state(Symmetric(arr2ptr(e_np1)), + Symmetric(arr2ptr(e_n)), T_np1, T_n, t_np1, t_n, - arr2ptr(s_n), - arr2ptr(h_n), - u_n, p_n, *ts); - - return ts; + Symmetric(arr2ptr(s_n)), + m.gather_state_(arr2ptr(h_n)), + u_n, p_n); }, "Make a trial state, mostly for testing.") ; diff --git a/src/general_flow.cxx b/src/general_flow.cxx index 4174a708..b2fb90cc 100644 --- a/src/general_flow.cxx +++ b/src/general_flow.cxx @@ -10,17 +10,15 @@ namespace neml { GeneralFlowRule::GeneralFlowRule(ParameterSet & params) : - NEMLObject(params) + HistoryNEMLObject(params) { } -void GeneralFlowRule::work_rate(const double * const s, - const double * const alpha, - const double * const edot, double T, - double Tdot, double & p_dot) +double GeneralFlowRule::work_rate(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { // By default don't calculate plastic work - p_dot = 0.0; + return 0.0; } void GeneralFlowRule::set_elastic_model(std::shared_ptr @@ -38,7 +36,7 @@ TVPFlowRule::TVPFlowRule(ParameterSet & params) : elastic_(params.get_object_parameter("elastic")), flow_(params.get_object_parameter("flow")) { - + cache_history_(); } std::string TVPFlowRule::type() @@ -62,279 +60,193 @@ std::unique_ptr TVPFlowRule::initialize(ParameterSet & params) } -size_t TVPFlowRule::nhist() const +void TVPFlowRule::populate_hist(History & h) const { - return flow_->nhist(); + flow_->set_variable_prefix(get_variable_prefix()); + flow_->populate_hist(h); } -void TVPFlowRule::init_hist(double * const h) +void TVPFlowRule::init_hist(History & h) const { flow_->init_hist(h); - } -void TVPFlowRule::s(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const sdot) +Symmetric TVPFlowRule::s(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { - double erate[6]; - std::copy(edot, edot+6, erate); - - double temp[6]; + Symmetric temp; double yv; - flow_->g(s, alpha, T, temp); - flow_->y(s, alpha, T, yv); + flow_->g(s.data(), alpha.rawptr(), T, temp.s()); + flow_->y(s.data(), alpha.rawptr(), T, yv); if (yv > NEML_STRAIN_RATE_LIMIT) throw NEMLError("Strain rate exceeds rate limit"); - for (int i=0; i<6; i++) { - erate[i] -= yv * temp[i]; - } - - flow_->g_temp(s, alpha, T, temp); - for (int i=0; i<6; i++) { - erate[i] -= Tdot * temp[i]; - } - - flow_->g_time(s, alpha, T, temp); - for (int i=0; i<6; i++) { - erate[i] -= temp[i]; - } - - double C[36]; - elastic_->C(T, C); + Symmetric erate = edot - yv * temp; - mat_vec(C, 6, erate, 6, sdot); + flow_->g_temp(s.data(), alpha.rawptr(), T, temp.s()); + erate -= Tdot * temp; + flow_->g_time(s.data(), alpha.rawptr(), T, temp.s()); + erate -= temp; + return elastic_->C(T).dot(erate); } -void TVPFlowRule::ds_ds(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot) +SymSymR4 TVPFlowRule::ds_ds(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { double yv; - flow_->y(s, alpha, T, yv); - - double work[36]; - flow_->dg_ds(s, alpha, T, work); - for (int i=0; i<36; i++) { - work[i] *= -yv; - } - - double t1[6]; - flow_->g(s, alpha, T, t1); - double t2[6]; - flow_->dy_ds(s, alpha, T, t2); - outer_update_minus(t1, 6, t2, 6, work); - - double t3[36]; - flow_->dg_ds_temp(s, alpha, T, t3); - for (int i=0; i<36; i++) { - work[i] -= t3[i] * Tdot; - } + flow_->y(s.data(), alpha.rawptr(), T, yv); - flow_->dg_ds_time(s, alpha, T, t3); - for (int i=0; i<36; i++) { - work[i] -= t3[i]; - } + SymSymR4 work; + flow_->dg_ds(s.data(), alpha.rawptr(), T, work.s()); + work *= -yv; - elastic_->C(T, t3); - - mat_mat(6,6,6, t3, work, d_sdot); + Symmetric t1, t2; + flow_->g(s.data(), alpha.rawptr(), T, t1.s()); + flow_->dy_ds(s.data(), alpha.rawptr(), T, t2.s()); + work -= douter(t1, t2); + SymSymR4 t3; + flow_->dg_ds_temp(s.data(), alpha.rawptr(), T, t3.s()); + work -= t3 * Tdot; + + flow_->dg_ds_time(s.data(), alpha.rawptr(), T, t3.s()); + work -= t3; + return elastic_->C(T).dot(work); } -void TVPFlowRule::ds_da(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot) +History TVPFlowRule::ds_da(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { double yv; - flow_->y(s, alpha, T, yv); + flow_->y(s.data(), alpha.rawptr(), T, yv); - int sz = 6 * nhist(); + History work = gather_blank_history_().derivative(); + flow_->dg_da(s.data(), alpha.rawptr(), T, work.rawptr()); + work *= -yv; - std::vector workv(sz); - double * work = &workv[0]; - flow_->dg_da(s, alpha, T, work); - for (int i=0; ig(s, alpha, T, t1); - std::vector t2v(nhist()); - double * t2 = &t2v[0]; - flow_->dy_da(s, alpha, T, t2); - outer_update_minus(t1, 6, t2, nhist(), work); + // Ugh, we need to make these matrices... + Symmetric t1; + flow_->g(s.data(), alpha.rawptr(), T, t1.s()); + History t2 = gather_blank_history_(); + flow_->dy_da(s.data(), alpha.rawptr(), T, t2.rawptr()); + outer_update_minus(t1.data(), 6, t2.rawptr(), nhist(), work.rawptr()); - std::vector t3v(sz); - double * t3 = &t3v[0]; - flow_->dg_da_temp(s, alpha, T, t3); - for (int i=0; idg_da_time(s, alpha, T, t3); - for (int i=0; iC(T, C); - - mat_mat(6, nhist(), 6, C, work, d_sdot); + History t3 = gather_blank_history_().derivative(); + flow_->dg_da_temp(s.data(), alpha.rawptr(), T, t3.rawptr()); + work -= t3 * Tdot; + flow_->dg_da_time(s.data(), alpha.rawptr(), T, t3.rawptr()); + work -= t3; + + SymSymR4 C = elastic_->C(T); + return work.premultiply(C); } -void TVPFlowRule::ds_de(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot) +SymSymR4 TVPFlowRule::ds_de(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { - elastic_->C(T, d_sdot); + return elastic_->C(T); } -void TVPFlowRule::a(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const adot) +History TVPFlowRule::a(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { double dg; - flow_->y(s, alpha, T, dg); - - flow_->h(s, alpha, T, adot); - for (size_t i=0; iy(s.data(), alpha.rawptr(), T, dg); - std::vector tempv(nhist()); - double * temp = &tempv[0]; - flow_->h_temp(s, alpha, T, temp); - for (size_t i=0; ih_time(s, alpha, T, temp); - for (size_t i=0; ih(s.data(), alpha.rawptr(), T, adot.rawptr()); + adot *= dg; + + History temp = gather_blank_history_(); + flow_->h_temp(s.data(), alpha.rawptr(), T, temp.rawptr()); + adot += temp * Tdot; + flow_->h_time(s.data(), alpha.rawptr(), T, temp.rawptr()); + adot += temp; + return adot; } -void TVPFlowRule::da_ds(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot) +History TVPFlowRule::da_ds(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { double dg; - flow_->y(s, alpha, T, dg); - - int sz = nhist() * 6; - - flow_->dh_ds(s, alpha, T, d_adot); - for (int i=0; i t1v(nhist()); - double * t1 = &t1v[0]; - flow_->h(s, alpha, T, t1); + flow_->y(s.data(), alpha.rawptr(), T, dg); - double t2[6]; - flow_->dy_ds(s, alpha, T, t2); - - outer_update(t1, nhist(), t2, 6, d_adot); + History d_adot = gather_blank_history_().derivative(); + flow_->dh_ds(s.data(), alpha.rawptr(), T, d_adot.rawptr()); + d_adot *= dg; - std::vector t3v(sz); - double * t3 = &t3v[0]; - flow_->dh_ds_temp(s, alpha, T, t3); - for (int i=0; idh_ds_time(s, alpha, T, t3); - for (int i=0; ih(s.data(), alpha.rawptr(), T, t1.rawptr()); + Symmetric t2; + flow_->dy_ds(s.data(), alpha.rawptr(), T, t2.s()); + outer_update(t1.rawptr(), nhist(), t2.data(), 6, d_adot.rawptr()); + History t3 = gather_blank_history_().derivative(); + flow_->dh_ds_temp(s.data(), alpha.rawptr(), T, t3.rawptr()); + d_adot += t3 * Tdot; + + flow_->dh_ds_time(s.data(), alpha.rawptr(), T, t3.rawptr()); + return d_adot + t3; } -void TVPFlowRule::da_da(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot) +History TVPFlowRule::da_da(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { double dg; - flow_->y(s, alpha, T, dg); + flow_->y(s.data(), alpha.rawptr(), T, dg); int nh = nhist(); - int sz = nh * nh; - - flow_->dh_da(s, alpha, T, d_adot); - for (int i=0; i t1v(nh); - double * t1 = &t1v[0]; - flow_->h(s, alpha, T, t1); + History d_adot = gather_blank_history_().derivative(); + flow_->dh_da(s.data(), alpha.rawptr(), T, d_adot.rawptr()); + d_adot *= dg; - std::vector t2v(nh); - double * t2 = &t2v[0]; - flow_->dy_da(s, alpha, T, t2); - - outer_update(t1, nh, t2, nh, d_adot); + // Ugh + History t1 = gather_blank_history_(); + flow_->h(s.data(), alpha.rawptr(), T, t1.rawptr()); + History t2 = gather_blank_history_(); + flow_->dy_da(s.data(), alpha.rawptr(), T, t2.rawptr()); + outer_update(t1.rawptr(), nh, t2.rawptr(), nh, d_adot.rawptr()); - std::vector t3v(sz); - double * t3 = &t3v[0]; - flow_->dh_da_temp(s, alpha, T, t3); - for (int i=0; idh_da_time(s, alpha, T, t3); - for (int i=0; i(); + flow_->dh_da_temp(s.data(), alpha.rawptr(), T, t3.rawptr()); + d_adot += t3 * Tdot; + + flow_->dh_da_time(s.data(), alpha.rawptr(), T, t3.rawptr()); + return d_adot + t3; } -void TVPFlowRule::da_de(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot) +History TVPFlowRule::da_de(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { - std::fill(d_adot, d_adot+(nhist()*6), 0.0); - + return gather_blank_history_().derivative(); } -void TVPFlowRule::work_rate(const double * const s, - const double * const alpha, - const double * const edot, double T, - double Tdot, double & p_dot) +double TVPFlowRule::work_rate(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { - double erate[6]; - std::fill(erate, erate+6, 0.0); - - double temp[6]; + Symmetric dir; double yv; - flow_->g(s, alpha, T, temp); - flow_->y(s, alpha, T, yv); - - for (int i=0; i<6; i++) { - erate[i] += yv * temp[i]; - } - - flow_->g_temp(s, alpha, T, temp); - for (int i=0; i<6; i++) { - erate[i] += Tdot * temp[i]; - } + flow_->g(s.data(), alpha.rawptr(), T, dir.s()); + flow_->y(s.data(), alpha.rawptr(), T, yv); - flow_->g_time(s, alpha, T, temp); - for (int i=0; i<6; i++) { - erate[i] += temp[i]; - } + Symmetric erate = yv * dir; - p_dot = dot_vec(s, erate, 6); -} - -void TVPFlowRule::elastic_strains(const double * const s_np1, double T_np1, - double * const e_np1) const -{ - double S[36]; - elastic_->S(T_np1, S); - mat_vec(S, 6, s_np1, 6, e_np1); + flow_->g_temp(s.data(), alpha.rawptr(), T, dir.s()); + erate += Tdot * dir; + flow_->g_time(s.data(), alpha.rawptr(), T, dir.s()); + erate += dir; + + return s.contract(erate); } void TVPFlowRule::set_elastic_model(std::shared_ptr emodel) diff --git a/src/general_flow_wrap.cxx b/src/general_flow_wrap.cxx index 2cc00e3b..6c41a718 100644 --- a/src/general_flow_wrap.cxx +++ b/src/general_flow_wrap.cxx @@ -14,102 +14,22 @@ PYBIND11_MODULE(general_flow, m) { m.doc() = "General flow models where subclass functions define everything."; - py::class_>(m, "GeneralFlowRule") - .def_property_readonly("nhist", &GeneralFlowRule::nhist, "Number of history variables.") - .def("init_hist", - [](GeneralFlowRule & m) -> py::array_t - { - auto h = alloc_vec(m.nhist()); - m.init_hist(arr2ptr(h)); - return h; - }, "Initialize history variables.") - - .def("s", - [](GeneralFlowRule & m, py::array_t s, py::array_t alpha, py::array_t edot, double T, double Tdot) -> py::array_t - { - auto f = alloc_vec(6); - m.s(arr2ptr(s), arr2ptr(alpha), - arr2ptr(edot), T, - Tdot, - arr2ptr(f)); - return f; - }, "Stress rate.") - .def("ds_ds", - [](GeneralFlowRule & m, py::array_t s, py::array_t alpha, py::array_t edot, double T, double Tdot) -> py::array_t - { - auto f = alloc_mat(6,6); - m.ds_ds(arr2ptr(s), arr2ptr(alpha), - arr2ptr(edot), T, - Tdot, arr2ptr(f)); - return f; - }, "Stress rate derivative with respect to stress.") - .def("ds_da", - [](GeneralFlowRule & m, py::array_t s, py::array_t alpha, py::array_t edot, double T, double Tdot) -> py::array_t - { - auto f = alloc_mat(6,m.nhist()); - m.ds_da(arr2ptr(s), arr2ptr(alpha), - arr2ptr(edot), T, - Tdot, arr2ptr(f)); - return f; - }, "Stress rate derivative with respect to history.") - .def("ds_de", - [](GeneralFlowRule & m, py::array_t s, py::array_t alpha, py::array_t edot, double T, double Tdot) -> py::array_t - { - auto f = alloc_mat(6,6); - m.ds_de(arr2ptr(s), arr2ptr(alpha), - arr2ptr(edot), T, - Tdot, arr2ptr(f)); - return f; - }, "Stress rate derivative with respect to strain.") - - - .def("a", - [](GeneralFlowRule & m, py::array_t s, py::array_t alpha, py::array_t edot, double T, double Tdot) -> py::array_t - { - auto f = alloc_vec(m.nhist()); - m.a(arr2ptr(s), arr2ptr(alpha), - arr2ptr(edot), T, - Tdot, - arr2ptr(f)); - return f; - }, "History rate.") - .def("da_ds", - [](GeneralFlowRule & m, py::array_t s, py::array_t alpha, py::array_t edot, double T, double Tdot) -> py::array_t - { - auto f = alloc_mat(m.nhist(),6); - m.da_ds(arr2ptr(s), arr2ptr(alpha), - arr2ptr(edot), T, - Tdot, arr2ptr(f)); - return f; - }, "History rate derivative with respect to stress.") - .def("da_da", - [](GeneralFlowRule & m, py::array_t s, py::array_t alpha, py::array_t edot, double T, double Tdot) -> py::array_t - { - auto f = alloc_mat(m.nhist(),m.nhist()); - m.da_da(arr2ptr(s), arr2ptr(alpha), - arr2ptr(edot), T, - Tdot, arr2ptr(f)); - return f; - }, "History rate derivative with respect to history.") - .def("da_de", - [](GeneralFlowRule & m, py::array_t s, py::array_t alpha, py::array_t edot, double T, double Tdot) -> py::array_t - { - auto f = alloc_mat(m.nhist(),6); - m.da_de(arr2ptr(s), arr2ptr(alpha), - arr2ptr(edot), T, - Tdot, arr2ptr(f)); - return f; - }, "History rate derivative with respect to strain.") - - .def("work_rate", - [](GeneralFlowRule & m, py::array_t s, py::array_t alpha, py::array_t edot, double T, double Tdot) -> double - { - double pi; - m.work_rate(arr2ptr(s), arr2ptr(alpha), - arr2ptr(edot), T, - Tdot, pi); - return pi; - }, "Plastic work rate.") + py::class_>(m, "GeneralFlowRule") + .def("s", &GeneralFlowRule::s, "Stress rate") + .def("ds_ds", &GeneralFlowRule::ds_ds, "Stress rate derivative with respect " + "to stress.") + .def("ds_da", &GeneralFlowRule::ds_da, "Stress rate derivative with respect " + "to history.") + .def("ds_de", &GeneralFlowRule::ds_de, "Stress rate derivative with respect " + "to strain rate.") + .def("a", &GeneralFlowRule::a, "History rate.") + .def("da_ds", &GeneralFlowRule::da_ds, "History rate derivative with respect " + "to stress.") + .def("da_da", &GeneralFlowRule::da_da, "History rate derivative with respect " + "to history.") + .def("da_de", &GeneralFlowRule::da_de, "History rate derivative with respect " + "to strain rate.") + .def("work_rate", &GeneralFlowRule::work_rate, "Inelastic work rate.") .def("set_elastic_model", &GeneralFlowRule::set_elastic_model) ; diff --git a/src/hardening.cxx b/src/hardening.cxx index 9d2f5386..31fc9133 100644 --- a/src/hardening.cxx +++ b/src/hardening.cxx @@ -10,7 +10,7 @@ namespace neml { HardeningRule::HardeningRule(ParameterSet & params) : - NEMLObject(params) + HistoryNEMLObject(params) { } @@ -21,15 +21,14 @@ IsotropicHardeningRule::IsotropicHardeningRule(ParameterSet & params) : } -size_t IsotropicHardeningRule::nhist() const +void IsotropicHardeningRule::populate_hist(History & h) const { - return 1; + h.add(prefix("alpha")); } -void IsotropicHardeningRule::init_hist(double * const alpha) const +void IsotropicHardeningRule::init_hist(History & h) const { - alpha[0] = 0.0; - + h.get(prefix("alpha")) = 0.0; } // Implementation of linear hardening @@ -303,15 +302,14 @@ KinematicHardeningRule::KinematicHardeningRule(ParameterSet & params) : } // Implementation of kinematic base class -size_t KinematicHardeningRule::nhist() const +void KinematicHardeningRule::populate_hist(History & hist) const { - return 6; + hist.add(prefix("backstress")); } -void KinematicHardeningRule::init_hist(double * const alpha) const +void KinematicHardeningRule::init_hist(History & hist) const { - for (int i=0; i<6; i++) alpha[i] = 0.0; - + hist.get(prefix("backstress")) = Symmetric::zero(); } // Implementation of linear kinematic hardening @@ -344,7 +342,7 @@ std::unique_ptr LinearKinematicHardeningRule::initialize(ParameterSe void LinearKinematicHardeningRule::q(const double * const alpha, double T, double * const qv) const { - for (int i=0; i<6; i++) { + for (size_t i=0; i<6; i++) { qv[i] = -H_->value(T) * alpha[i]; } @@ -354,7 +352,7 @@ void LinearKinematicHardeningRule::dq_da(const double * const alpha, double T, double * const dqv) const { std::fill(dqv, dqv+36, 0.0); - for (int i=0; i<6; i++) { + for (size_t i=0; i<6; i++) { dqv[CINDEX(i,i,6)] = -H_->value(T); } @@ -393,15 +391,16 @@ std::unique_ptr CombinedHardeningRule::initialize(ParameterSet & par return neml::make_unique(params); } -size_t CombinedHardeningRule::nhist() const +void CombinedHardeningRule::populate_hist(History & hist) const { - return iso_->nhist() + kin_->nhist(); + iso_->populate_hist(hist); + kin_->populate_hist(hist); } -void CombinedHardeningRule::init_hist(double * const alpha) const +void CombinedHardeningRule::init_hist(History & hist) const { - iso_->init_hist(alpha); - return kin_->init_hist(&alpha[iso_->nhist()]); + iso_->init_hist(hist); + kin_->init_hist(hist); } void CombinedHardeningRule::q(const double * const alpha, double T, @@ -441,7 +440,7 @@ void CombinedHardeningRule::dq_da(const double * const alpha, double T, } NonAssociativeHardening::NonAssociativeHardening(ParameterSet & params) : - NEMLObject(params) + HistoryNEMLObject(params) { } @@ -641,14 +640,18 @@ size_t Chaboche::ninter() const return 1 + 6; } -size_t Chaboche::nhist() const +void Chaboche::populate_hist(History & h) const { - return 1 + 6 * n_; + h.add(prefix("alpha")); + for (size_t i = 0; i < n_; i++) + h.add(prefix("backstress_"+std::to_string(i))); } -void Chaboche::init_hist(double * const alpha) const +void Chaboche::init_hist(History & h) const { - std::fill(alpha, alpha+nhist(), 0.0); + h.get(prefix("alpha")) = 0.0; + for (size_t i = 0; i < n_; i++) + h.get(prefix("backstress_"+std::to_string(i))) = Symmetric::zero(); } void Chaboche::q(const double * const alpha, double T, double * const qv) const @@ -657,10 +660,10 @@ void Chaboche::q(const double * const alpha, double T, double * const qv) const std::fill(qv+1, qv+7, 0.0); // Helps with unrolling - int n = n_; + size_t n = n_; - for (int i=0; idq_da(alpha, T, qv); // fills in (0,0) // Help unroll - int n = n_; + size_t n = n_; - for (int i=0; i c = eval_vector(c_, T); - for (int i=0; igamma(alpha[0], T) * alpha[1+i*6+j]; } } @@ -726,13 +729,13 @@ void Chaboche::dh_ds(const double * const s, const double * const alpha, double double nn[36]; std::fill(nn, nn+36, 0.0); - for (int i=0; i<6; i++) { + for (size_t i=0; i<6; i++) { nn[CINDEX(i,i,6)] += 1.0; } double iv[6]; double jv[6]; - for (int i=0; i<3; i++) { + for (size_t i=0; i<3; i++) { iv[i] = 1.0 / 3.0; jv[i] = 1.0; } @@ -745,14 +748,14 @@ void Chaboche::dh_ds(const double * const s, const double * const alpha, double outer_update_minus(n, 6, n, 6, nn); if (nv != 0.0) { - for (int i=0; i<36; i++) { + for (size_t i=0; i<36; i++) { nn[i] /= nv; } } // Fill in... - for (int i=0; igamma(alpha[0], T); } } // Fill in the ss part - for (int bi=0; bidgamma(alpha[0], T) * alpha[1+i*6+j]; } @@ -833,10 +836,10 @@ void Chaboche::h_time(const double * const s, const double * const alpha, double Xi[6]; double nXi; - for (int i=0; i A = eval_vector(A_, T); std::vector a = eval_vector(a_, T); - int nh = nhist(); - int n = n_; + size_t nh = nhist(); + size_t n = n_; double XX[36]; double Xi[6]; double nXi; int ia,ib; double d; - for (int i=0; i c = eval_vector(c_, T); std::vector dc = eval_deriv_vector(c_, T); - for (int i=0; i c = eval_vector(c_, T); std::vector dc = eval_deriv_vector(c_, T); - for (int i=0; i Chaboche::c(double T) const void Chaboche::backstress_(const double * const alpha, double * const X) const { std::fill(X, X+6, 0.0); - for (int i=0; i(prefix("alpha")); + for (size_t i = 0; i < n_; i++) + h.add(prefix("backstress_"+std::to_string(i))); } -void ChabocheVoceRecovery::init_hist(double * const alpha) const +void ChabocheVoceRecovery::init_hist(History & h) const { - std::fill(alpha, alpha+nhist(), 0.0); + h.get(prefix("alpha")) = 0.0; + for (size_t i = 0; i < n_; i++) + h.get(prefix("backstress_"+std::to_string(i))) = Symmetric::zero(); } void ChabocheVoceRecovery::q(const double * const alpha, double T, double * const qv) const @@ -1027,10 +1034,10 @@ void ChabocheVoceRecovery::q(const double * const alpha, double T, double * cons std::fill(qv+1, qv+7, 0.0); // Helps with unrolling - int n = n_; + size_t n = n_; - for (int i=0; i c = eval_vector(c_, T); - for (int i=0; igamma(alpha[0], T) * alpha[1+i*6+j]; } } @@ -1100,13 +1107,13 @@ void ChabocheVoceRecovery::dh_ds(const double * const s, const double * const al double nn[36]; std::fill(nn, nn+36, 0.0); - for (int i=0; i<6; i++) { + for (size_t i=0; i<6; i++) { nn[CINDEX(i,i,6)] += 1.0; } double iv[6]; double jv[6]; - for (int i=0; i<3; i++) { + for (size_t i=0; i<3; i++) { iv[i] = 1.0 / 3.0; jv[i] = 1.0; } @@ -1119,14 +1126,14 @@ void ChabocheVoceRecovery::dh_ds(const double * const s, const double * const al outer_update_minus(n, 6, n, 6, nn); if (nv != 0.0) { - for (int i=0; i<36; i++) { + for (size_t i=0; i<36; i++) { nn[i] /= nv; } } // Fill in... - for (int i=0; igamma(alpha[0], T); } } // Fill in the ss part - for (int bi=0; bidgamma(alpha[0], T) * alpha[1+i*6+j]; } @@ -1214,10 +1221,10 @@ void ChabocheVoceRecovery::h_time(const double * const s, const double * const a double Xi[6]; double nXi; - for (int i=0; i A = eval_vector(A_, T); std::vector a = eval_vector(a_, T); - int nh = nhist(); - int n = n_; + size_t nh = nhist(); + size_t n = n_; double XX[36]; double Xi[6]; double nXi; int ia,ib; double d; - for (int i=0; i c = eval_vector(c_, T); std::vector dc = eval_deriv_vector(c_, T); - for (int i=0; i c = eval_vector(c_, T); std::vector dc = eval_deriv_vector(c_, T); - for (int i=0; i>(m, "HardeningRule") - .def_property_readonly("nhist", &HardeningRule::nhist, "Number of history variables.") - - .def("init_hist", - [](const HardeningRule & m) -> py::array_t - { - auto v = alloc_vec(m.nhist()); - m.init_hist(arr2ptr(v)); - return v; - }, "Initialize history.") - + py::class_>(m, "HardeningRule") .def("q", [](const HardeningRule & m, py::array_t alpha, double T) -> py::array_t { @@ -126,17 +116,8 @@ PYBIND11_MODULE(hardening, m) { })) ; - py::class_>(m, "NonAssociativeHardening") + py::class_>(m, "NonAssociativeHardening") .def_property_readonly("ninter", &NonAssociativeHardening::ninter, "Number of q variables.") - .def_property_readonly("nhist", &NonAssociativeHardening::nhist, "Number of a variables.") - - .def("init_hist", - [](const NonAssociativeHardening & m) -> py::array_t - { - auto v = alloc_vec(m.nhist()); - m.init_hist(arr2ptr(v)); - return v; - }, "Initialize history.") .def("q", [](const NonAssociativeHardening & m, py::array_t alpha, double T) -> py::array_t diff --git a/src/history.cxx b/src/history.cxx index 14e26084..a3459b58 100644 --- a/src/history.cxx +++ b/src/history.cxx @@ -182,11 +182,18 @@ void History::increase_store(size_t newsize) storage_ = newstore; } -void History::scalar_multiply(double scalar) +History & History::operator*=(const double & scalar) +{ + return scalar_multiply(scalar); +} + +History & History::scalar_multiply(const double & scalar) { for (size_t i = 0; i < size_; i++) { storage_[i] *= scalar; } + + return *this; } History & History::operator+=(const History & other) @@ -200,6 +207,20 @@ History & History::operator+=(const History & other) return *this; } +History History::operator-() const +{ + History cpy = deepcopy(); + for (size_t i = 0; i < size_; i++) + cpy.rawptr()[i] = -cpy.rawptr()[i]; + + return cpy; +} + +History & History::operator-=(const History & other) +{ + return this->operator+=(-other); +} + History History::copy_blank(std::vector exclude) const { History copy; @@ -358,6 +379,19 @@ History & History::reorder(std::vector vars) return *this; } +History History::premultiply(const SymSymR4 & T) +{ + // This is a hack, really we would need to make sure each object is + // conformal + if (size_ % 6 != 0) + throw std::runtime_error("History object does not appear to be suitable " + "for premultiplication by a SymSymR4!"); + History nhist = this->deepcopy(); + mat_mat(6, size_ / 6, 6, T.data(), storage_, nhist.rawptr()); + + return nhist; +} + History History::postmultiply(const SymSymR4 & T) { // This is not a guarantee that this object has the right form, @@ -413,4 +447,97 @@ double * History::start_loc(std::string name) return &(storage_[loc_.at(name)]); } +History operator*(const double & s, const History & v) +{ + History cpy = v.deepcopy(); + cpy *= s; + return cpy; +} + +History operator*(const History & v, const double & s) +{ + return operator*(s, v); +} + +History operator+(const History & a, const History & b) +{ + History res = a.deepcopy(); + return res+=b; +} + +History operator-(const History & a, const History & b) +{ + History res = a.deepcopy(); + return res-=b; +} + +HistoryNEMLObject::HistoryNEMLObject(ParameterSet & params) : + NEMLObject(params), prefix_("") +{ + +} + +size_t HistoryNEMLObject::nhist() const +{ + History h; + populate_hist(h); + return h.size(); +} + +void HistoryNEMLObject::init_store(double * const h) const +{ + History hist(h); + populate_hist(hist); + init_hist(hist); +} + +size_t HistoryNEMLObject::nstore() const +{ + return nhist(); +} + +void HistoryNEMLObject::set_variable_prefix(std::string prefix) +{ + prefix_ = prefix; +} + +std::string HistoryNEMLObject::get_variable_prefix() const +{ + return prefix_; +} + +std::string HistoryNEMLObject::prefix(std::string basename) const +{ + return prefix_ + basename; +} + +std::string HistoryNEMLObject::dprefix(std::string a, std::string b) const +{ + return prefix(a) + "_" + prefix(b); +} + +void HistoryNEMLObject::cache_history_() +{ + populate_hist(stored_hist_); +} + +History HistoryNEMLObject::gather_history_(double * data) const +{ + History h = gather_blank_history_(); + h.set_data(data); + return h; +} + +History HistoryNEMLObject::gather_history_(const double * data) const +{ + History h = gather_blank_history_(); + h.set_data(const_cast(data)); + return h; +} + +History HistoryNEMLObject::gather_blank_history_() const +{ + return stored_hist_; +} + } // namespace neml diff --git a/src/history_wrap.cxx b/src/history_wrap.cxx index d3385b47..0cdd2dc8 100644 --- a/src/history_wrap.cxx +++ b/src/history_wrap.cxx @@ -11,6 +11,8 @@ namespace neml { PYBIND11_MODULE(history, m) { m.doc() = "Internal variable tracking system."; + py::module::import("neml.objects"); + py::class_>(m, "History", py::buffer_protocol()) .def(py::init<>()) @@ -156,6 +158,34 @@ PYBIND11_MODULE(history, m) { return mat; }, "Unravel to c-style array") ; + py::class_>(m, "HistoryNEMLObject") + .def("populate_hist", &HistoryNEMLObject::populate_hist, + "Populate a blank history object with the names/types") + .def("init_hist", &HistoryNEMLObject::init_hist, + "Initialize the history with the initial conditions") + .def_property_readonly("nstore", &HistoryNEMLObject::nstore, + "Number of variables the program needs to store.") + .def("init_store", + [](HistoryNEMLObject & m) -> py::array_t + { + auto h = alloc_vec(m.nstore()); + m.init_store(arr2ptr(h)); + return h; + }, "Initialize stored variables.") + .def("initial_history", [](HistoryNEMLObject & m) -> History + { + History h; + m.populate_hist(h); + m.init_hist(h); + return h; + }, "Return a fully initialized history object") + .def_property_readonly("nhist", &HistoryNEMLObject::nhist, + "Number of internal variables") + .def_property("variable_prefix", &HistoryNEMLObject::get_variable_prefix, + &HistoryNEMLObject::set_variable_prefix) + .def("prefix", &HistoryNEMLObject::prefix) + ; } } // namespace neml diff --git a/src/math/tensors.cxx b/src/math/tensors.cxx index fca8d015..ef17030b 100644 --- a/src/math/tensors.cxx +++ b/src/math/tensors.cxx @@ -2168,4 +2168,14 @@ SymSymSymR6 outer_product_k(const SymSymR4 & A, const Symmetric & B) return res; } +Symmetric truesdell_update_sym(const Symmetric & D, const Skew & W, + const Symmetric & cauchy_n, + const Symmetric & dS) +{ + Symmetric res; + truesdell_update_sym(D.data(), W.data(), cauchy_n.data(), dS.data(), + res.s()); + return res; +} + } // namespace neml diff --git a/src/models.cxx b/src/models.cxx index cf4fb200..aa96f763 100644 --- a/src/models.cxx +++ b/src/models.cxx @@ -11,11 +11,66 @@ namespace neml { NEMLModel::NEMLModel(ParameterSet & params) : - NEMLObject(params) + HistoryNEMLObject(params) { } +void NEMLModel::update_sd( + const double * const e_np1, const double * const e_n, + double T_np1, double T_n, + double t_np1, double t_n, + double * const s_np1, const double * const s_n, + double * const h_np1, const double * const h_n, + double * const A_np1, + double & u_np1, double u_n, + double & p_np1, double p_n) +{ + // Wrap everything and just call the interface + Symmetric E_np1(e_np1); + Symmetric E_n(e_n); + + Symmetric S_np1(s_np1); + Symmetric S_n(s_n); + + History H_np1 = gather_history_(h_np1); + History H_n = gather_history_(h_n); + + SymSymR4 A(A_np1); + + update_sd_interface(E_np1, E_n, T_np1, T_n, t_np1, t_n, S_np1, S_n, + H_np1, H_n, A, u_np1, u_n, p_np1, p_n); +} + +void NEMLModel::update_ld_inc( + const double * const d_np1, const double * const d_n, + const double * const w_np1, const double * const w_n, + double T_np1, double T_n, + double t_np1, double t_n, + double * const s_np1, const double * const s_n, + double * const h_np1, const double * const h_n, + double * const A_np1, double * const B_np1, + double & u_np1, double u_n, + double & p_np1, double p_n) +{ + // Wrap everything and just call the interface + Symmetric D_np1(d_np1); + Symmetric D_n(d_n); + Skew W_np1(w_np1); + Skew W_n(w_n); + Symmetric S_np1(s_np1); + Symmetric S_n(s_n); + SymSymR4 A(A_np1); + SymSkewR4 B(B_np1); + + History H_np1 = gather_history_(h_np1); + History H_n = gather_history_(h_n); + + update_ld_inc_interface(D_np1, D_n, W_np1, W_n, T_np1, T_n, t_np1, t_n, + S_np1, S_n, H_np1, H_n, A, B, u_np1, u_n, + p_np1, p_n); +} + void NEMLModel::save(std::string file_name, std::string model_name) { std::string representation = serialize(model_name, "materials"); @@ -24,9 +79,102 @@ void NEMLModel::save(std::string file_name, std::string model_name) outfile << representation; outfile.close(); } -double NEMLModel::get_damage(const double *const h_np1) { return 0.0; } -bool NEMLModel::should_del_element(const double *const h_np1) { return false; } -bool NEMLModel::is_damage_model() const { return false; } + +void NEMLModel::populate_hist(History & h) const +{ + populate_static(h); + populate_state(h); +} + +void NEMLModel::init_hist(History & h) const +{ + init_static(h); + init_state(h); +} + +void NEMLModel::populate_static(History & h) const +{ + // Nothing by default +} + +void NEMLModel::init_static(History & h) const +{ + // Nothing by default +} + +void NEMLModel::elastic_strains(const double * const s_np1, + double T_np1, const double * const h_np1, + double * const e_np1) const +{ + Symmetric S_np1(s_np1); + History H_np1 = gather_history_(h_np1); + Symmetric E_np1(e_np1); + E_np1 = elastic_strains_interface(S_np1, T_np1, H_np1); +} + +Symmetric NEMLModel::elastic_strains_interface(const Symmetric & s_np1, double T_np1, const History & h_np1) const +{ + return Symmetric(); +} + +double NEMLModel::get_damage(const double *const h_np1) +{ + return 0.0; +} + +bool NEMLModel::should_del_element(const double *const h_np1) +{ + return false; +} + +bool NEMLModel::is_damage_model() const +{ + return false; +} + +std::tuple NEMLModel::split_state(const History & h) const +{ + History h1 = h.split(stored_static_.items()); + History h2 = h.split(stored_static_.items(), false); + + return std::tie(h1,h2); +} + +size_t NEMLModel::nstate() const +{ + return stored_state_.size(); +} + +size_t NEMLModel::nstatic() const +{ + return stored_static_.size(); +} + +void NEMLModel::cache_history_() +{ + HistoryNEMLObject::cache_history_(); + populate_state(stored_state_); + populate_static(stored_static_); +} + +History NEMLModel::gather_state_(double * data) const +{ + History h = gather_blank_state_(); + h.set_data(data); + return h; +} + +History NEMLModel::gather_state_(const double * data) const +{ + History h = gather_blank_state_(); + h.set_data(const_cast(data)); + return h; +} + +History NEMLModel::gather_blank_state_() const +{ + return stored_state_; +} // NEMLModel_sd implementation NEMLModel_sd::NEMLModel_sd(ParameterSet & params) : @@ -38,51 +186,71 @@ NEMLModel_sd::NEMLModel_sd(ParameterSet & params) : } -void NEMLModel_sd::update_ld_inc( - const double * const d_np1, const double * const d_n, - const double * const w_np1, const double * const w_n, - double T_np1, double T_n, +void NEMLModel_sd::update_ld_inc_interface( + const Symmetric & d_np1, const Symmetric & d_n, + const Skew & w_np1, const Skew & w_n, + double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, double * const B_np1, + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, SymSkewR4 & B_np1, double & u_np1, double u_n, double & p_np1, double p_n) { - double base_A_np1[36]; - - double D[6]; - double W[3]; - double dS[6]; - - sub_vec(d_np1, d_n, 6, D); - sub_vec(w_np1, w_n, 3, W); + Symmetric D = d_np1 - d_n; + Skew W = w_np1 - w_n; + if (not truesdell_) + D = Symmetric::zero(); - // If not the Truesdell rate then use the Jaumann rate - if (not truesdell_) { - std::fill(D, D+6, 0.0); - } + SymSymR4 base_A_np1; + Symmetric stress_prime; + Symmetric stress_prime_n = h_n.get(prefix("small_stress")); + + update_sd_interface( + d_np1, d_n, + T_np1, T_n, t_np1, t_n, + stress_prime, + stress_prime_n, + h_np1, h_n, + base_A_np1, u_np1, u_n, p_np1, p_n); - update_sd(d_np1, d_n, T_np1, T_n, t_np1, t_n, &h_np1[nhist()], &h_n[nhist()], - &h_np1[0], &h_n[0], base_A_np1, u_np1, u_n, p_np1, p_n); - - sub_vec(&h_np1[nhist()], &h_n[nhist()], 6, dS); - - truesdell_update_sym(D, W, s_n, dS, s_np1); + h_np1.get(prefix("small_stress")) = stress_prime; + Symmetric dS = stress_prime - + h_n.get(prefix("small_stress")); + s_np1 = truesdell_update_sym(D, W, s_n, dS); calc_tangent_(D, W, base_A_np1, s_np1, A_np1, B_np1); +} +void NEMLModel_sd::update_sd_interface( + const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & s_np1, Symmetric & s_n, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, + double & u_np1, double u_n, + double & p_np1, double p_n) +{ + auto [H_np1, F_np1] = split_state(h_np1); + auto [H_n, F_n] = split_state(h_n); + + update_sd_state(e_np1, e_n, T_np1, T_n, t_np1, t_n, s_np1, s_n, + H_np1, H_n, + A_np1, u_np1, u_n, p_np1, p_n); } -size_t NEMLModel_sd::nstore() const +void NEMLModel_sd::init_static(History & h) const { - return nhist() + 6; + h.get(prefix("small_stress")) = Symmetric::zero(); } -void NEMLModel_sd::init_store(double * const store) const +void NEMLModel_sd::populate_static(History & h) const { - init_hist(&store[0]); - std::fill(&store[nhist()], &store[nhist()]+6, 0.0); + // This is a legacy from the old flat vector system. Composite models + // expect to only have this added one time. + if (!h.contains("small_stress")) + h.add(prefix("small_stress")); } double NEMLModel_sd::alpha(double T) const @@ -95,15 +263,9 @@ const std::shared_ptr NEMLModel_sd::elastic() const return elastic_; } -void NEMLModel_sd::elastic_strains(const double * const s_np1, - double T_np1, - const double * const h_np1, - double * const e_np1) const +Symmetric NEMLModel_sd::elastic_strains_interface(const Symmetric & s_np1, double T_np1, const History & h_np1) const { - double S[36]; - elastic_->S(T_np1, S); - mat_vec(S, 6, s_np1, 6, e_np1); - + return elastic_->S(T_np1).dot(s_np1); } void NEMLModel_sd::set_elastic_model(std::shared_ptr emodel) @@ -111,20 +273,20 @@ void NEMLModel_sd::set_elastic_model(std::shared_ptr emodel) elastic_ = emodel; } -void NEMLModel_sd::calc_tangent_(const double * const D, const double * const W, - const double * const C, const double * const S, - double * const A, double * const B) +void NEMLModel_sd::calc_tangent_(const Symmetric & D, const Skew & W, + const SymSymR4 & C, const Symmetric & S, + SymSymR4 & A, SymSkewR4 & B) { double J[81]; double O[81]; - truesdell_mat(D, W, J); + truesdell_mat(D.data(), W.data(), J); invert_mat(J, 9); - truesdell_tangent_outer(S, O); + truesdell_tangent_outer(S.data(), O); double F[81]; - mandel2full(C, F); + mandel2full(C.data(), F); double dL[81]; mat_mat(9,9,9, F, idsym, dL); @@ -140,11 +302,11 @@ void NEMLModel_sd::calc_tangent_(const double * const D, const double * const W, mat_mat(9,9,9, L, idsym, Dpart); mat_mat(9,9,9, L, idskew, Wpart); - full2mandel(Dpart, A); - full2skew(Wpart, B); + full2mandel(Dpart, A.s()); + full2skew(Wpart, B.s()); // IMPORTANT TODO: go back and find where you dropped the factor of 2... - for (int i=0; i<18; i++) B[i] *= 2.0; + for (int i=0; i<18; i++) B.s()[i] *= 2.0; } @@ -155,33 +317,23 @@ NEMLModel_ldi::NEMLModel_ldi(ParameterSet & params) : } -void NEMLModel_ldi::update_sd( - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, - double & u_np1, double u_n, - double & p_np1, double p_n) +void NEMLModel_ldi::update_sd_interface( + const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & s_np1, Symmetric & s_n, + History & h_np1, const History & h_n, + SymSymR4 & A_np1, + double & u_np1, double u_n, + double & p_np1, double p_n) { - double W[3] = {0,0,0}; - double B[18]; - update_ld_inc(e_np1, e_n, W, W, T_np1, T_n, t_np1, t_n, + Skew W; + SymSkewR4 B; + update_ld_inc_interface(e_np1, e_n, W, W, T_np1, T_n, t_np1, t_n, s_np1, s_n, h_np1, h_n, A_np1, B, u_np1, u_n, p_np1, p_n); } -size_t NEMLModel_ldi::nstore() const -{ - return nhist(); -} - -void NEMLModel_ldi::init_store(double * const store) const -{ - init_hist(&store[0]); -} - SubstepModel_sd::SubstepModel_sd(ParameterSet & params) : NEMLModel_sd(params), rtol_(params.get_parameter("rtol")), @@ -195,42 +347,38 @@ SubstepModel_sd::SubstepModel_sd(ParameterSet & params) : } -void SubstepModel_sd::update_sd( - const double * const e_np1, const double * const e_n, +void SubstepModel_sd::update_sd_state( + const Symmetric & E_np1, const Symmetric & E_n, double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, + Symmetric & S_np1, const Symmetric & S_n, + History & H_np1, const History & H_n, + SymSymR4 & AA_np1, double & u_np1, double u_n, double & p_np1, double p_n) { -// Setup the substep parameters + // Setup the substep parameters int nd = 0; // Number of times we subdivided int tf = pow(2, max_divide_); // Total integer step count int cm = tf; // Attempted integer step (sf = cm/tf) int cs = 0; // Accumulated steps // Strain, time, and temperature increments - double e_diff[6]; - sub_vec(e_np1, e_n, 6, e_diff); + Symmetric E_diff = E_np1 - E_n; double T_diff = T_np1 - T_n; double t_diff = t_np1 - t_n; // Previous subincrement quantities - double e_past[6]; - std::copy(e_n, e_n+6, e_past); - double s_past[6]; - std::copy(s_n, s_n+6, s_past); - double * h_past = new double [nhist()]; - std::copy(h_n, h_n+nhist(), h_past); + Symmetric E_past = E_n; + Symmetric S_past = S_n; + History H_past = H_n.deepcopy(); // We're not allowed to wrote to H_n, so need copy double T_past = T_n; double t_past = t_n; double u_past = u_n; double p_past = p_n; // Targets - double e_next[6]; + Symmetric E_next; double T_next; double t_next; @@ -246,15 +394,15 @@ void SubstepModel_sd::update_sd( // targets double sm = (double) (cs + cm) / (double) tf; double sf = (double) cm / (double) tf; - for (size_t i = 0; i<6; i++) e_next[i] = e_n[i] + sm * e_diff[i]; + E_next = E_n + sm * E_diff; T_next = T_n + sm * T_diff; t_next = t_n + sm * t_diff; try { // Try updating update_step( - e_next, e_past, T_next, T_past, t_next, t_past, s_np1, s_past, - h_np1, h_past, A_inc, E_inc, u_np1, u_past, p_np1, p_past); + E_next, E_past, T_next, T_past, t_next, t_past, S_np1, S_past, + H_np1, H_past, A_inc, E_inc, u_np1, u_past, p_np1, p_past); } // Failed adapt catch (const NEMLError & e) { @@ -281,9 +429,9 @@ void SubstepModel_sd::update_sd( // Succeeded: advance subincrement cs += cm; - std::copy(e_next, e_next+6, e_past); - std::copy(s_np1, s_np1+6, s_past); - std::copy(h_np1, h_np1+nhist(), h_past); + E_past = E_next; + S_past = S_np1; + H_past = H_np1; std::copy(A_new, A_new+(nparams()*6), A_old); T_past = T_next; @@ -295,43 +443,40 @@ void SubstepModel_sd::update_sd( // Extract the leading 6x6 part of the A matrix for (size_t i = 0; i < 6; i++) { for (size_t j = 0; j < 6; j++) { - A_np1[CINDEX(i,j,6)] = A_new[CINDEX(i,j,6)]; + AA_np1(i,j) = A_new[CINDEX(i,j,6)]; } } - delete [] h_past; delete [] A_inc; delete [] A_old; delete [] A_new; delete [] E_inc; - } void SubstepModel_sd::update_step( - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, + const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n, double * const A, double * const E, double & u_np1, double u_n, double & p_np1, double p_n) { // Setup the trial state - TrialState * ts = setup(e_np1, e_n, T_np1, T_n, t_np1, t_n, s_n, h_n); + std::unique_ptr ts = setup(e_np1, e_n, T_np1, T_n, t_np1, t_n, s_n, h_n); // Take an elastic step if the model requests it - if (elastic_step(ts, e_np1, e_n, T_np1, T_n, t_np1, t_n, s_n, h_n)) { - // Stress increment - double de[6]; - sub_vec(e_np1, e_n, 6, de); + if (elastic_step(ts.get(), e_np1, e_n, T_np1, T_n, t_np1, t_n, s_n, h_n)) { + // Strain increment + Symmetric de = e_np1 - e_n; - double C[36]; - elastic_->C(T_np1, C); - mat_vec(C, 6, de, 6, s_np1); - for (size_t i = 0; i < 6; i++) s_np1[i] += s_n[i]; + // Stress increment + SymSymR4 C = elastic_->C(T_np1); + s_np1 = C.dot(de) + s_n; + // History - std::copy(h_n, h_n+nhist(), h_np1); + h_np1 = h_n; + // Jacobian for substepping std::fill(A, A+(nparams()*nparams()), 0.0); for (size_t i = 0; i < 6; i++) A[CINDEX(i,i,nparams())] = 1.0; @@ -339,54 +484,68 @@ void SubstepModel_sd::update_step( std::fill(E, E+(nparams()*6), 0.0); for (size_t i = 0; i < 6; i++) { for (size_t j = 0; j < 6; j++) { - E[CINDEX(i,j,6)] = C[CINDEX(i,j,6)]; + E[CINDEX(i,j,6)] = C(i,j); } } // Energy and work - work_and_energy(ts, e_np1, e_n, T_np1, T_n, t_np1, t_n, s_np1, s_n, + work_and_energy(ts.get(), e_np1, e_n, T_np1, T_n, t_np1, t_n, s_np1, s_n, h_np1, h_n, u_np1, u_n, p_np1, p_n); - delete ts; - return; } // Solve the system - double * x = new double [nparams()]; + std::vector x(nparams()); try { - solve(this, x, ts, {rtol_, atol_, miter_, verbose_, linesearch_}, + solve(this, &x[0], ts.get(), {rtol_, atol_, miter_, verbose_, linesearch_}, nullptr, A); // Keep jacobian // Invert the Jacobian (or idk, could go in the tangent calc) invert_mat(A, nparams()); // Interpret the x vector as the updated state - update_internal(x, e_np1, e_n, T_np1, T_n, t_np1, t_n, + update_internal(&x[0], e_np1, e_n, T_np1, T_n, t_np1, t_n, s_np1, s_n, h_np1, h_n); // Get the dE matrix - strain_partial(ts, e_np1, e_n, T_np1, T_n, t_np1, t_n, s_np1, s_n, h_np1, h_n, E); + strain_partial(ts.get(), e_np1, e_n, T_np1, T_n, t_np1, t_n, s_np1, s_n, + h_np1, h_n, E); // Update the work and energy - work_and_energy(ts, e_np1, e_n, T_np1, T_n, t_np1, t_n, + work_and_energy(ts.get(), e_np1, e_n, T_np1, T_n, t_np1, t_n, s_np1, s_n, h_np1, h_n, u_np1, u_n, p_np1, p_n); } catch (const NEMLError & e) { - delete [] x; - delete ts; throw e; } +} + +void SubstepModel_sd::work_and_energy( + const TrialState * ts, + const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, + double t_np1, double t_n, + const Symmetric & s_np1, const Symmetric & s_n, + const History & h_np1, const History & h_n, + double & u_np1, double u_n, + double & p_np1, double p_n) +{ + Symmetric ep_np1 = e_np1 - elastic_->S(T_np1).dot(s_np1); + Symmetric ep_n = e_n - elastic_->S(T_n).dot(s_n); + + auto [du, dp] = trapezoid_energy(e_np1, e_n, ep_np1, ep_n, + s_np1, s_n); - delete [] x; - delete ts; + u_np1 = u_n + du; + p_np1 = p_n + dp; } // Implementation of small strain elasticity SmallStrainElasticity::SmallStrainElasticity(ParameterSet & params) : NEMLModel_sd(params) { - + cache_history_(); } std::string SmallStrainElasticity::type() @@ -412,37 +571,33 @@ std::unique_ptr SmallStrainElasticity::initialize(ParameterSet & par return neml::make_unique(params); } -size_t SmallStrainElasticity::nhist() const +void SmallStrainElasticity::populate_state(History & h) const { - return 0; } -void SmallStrainElasticity::init_hist(double * const hist) const +void SmallStrainElasticity::init_state(History & h) const { } -void SmallStrainElasticity::update_sd( - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, - double & u_np1, double u_n, - double & p_np1, double p_n) +void SmallStrainElasticity::update_sd_state( + const Symmetric & E_np1, const Symmetric & E_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & S_np1, const Symmetric & S_n, + History & H_np1, const History & H_n, + SymSymR4 & AA_np1, + double & u_np1, double u_n, + double & p_np1, double p_n) { - elastic_->C(T_np1, A_np1); - mat_vec(A_np1, 6, e_np1, 6, s_np1); - - // Energy calculation (trapezoid rule) - double de[6]; - double ds[6]; - sub_vec(e_np1, e_n, 6, de); - add_vec(s_np1, s_n, 6, ds); - for (int i=0; i<6; i++) ds[i] /= 2.0; - u_np1 = u_n + dot_vec(ds, de, 6); - p_np1 = p_n; + AA_np1 = elastic_->C(T_np1); + S_np1 = AA_np1.dot(E_np1); + auto [du, dp] = trapezoid_energy(E_np1, E_n, + Symmetric::zero(), + Symmetric::zero(), + S_np1, S_n); + u_np1 = u_n + du; + p_np1 = p_n + dp; } // Implementation of perfect plasticity @@ -451,7 +606,7 @@ SmallStrainPerfectPlasticity::SmallStrainPerfectPlasticity(ParameterSet & params surface_(params.get_object_parameter("surface")), ys_(params.get_object_parameter("ys")) { - + cache_history_(); } std::string SmallStrainPerfectPlasticity::type() @@ -487,104 +642,64 @@ std::unique_ptr SmallStrainPerfectPlasticity::initialize(ParameterSe return neml::make_unique(params); } -size_t SmallStrainPerfectPlasticity::nhist() const +void SmallStrainPerfectPlasticity::populate_state(History & h) const { - return 0; + } -void SmallStrainPerfectPlasticity::init_hist(double * const hist) const +void SmallStrainPerfectPlasticity::init_state(History & h) const { + } -TrialState * SmallStrainPerfectPlasticity::setup( - const double * const e_np1, const double * const e_n, +std::unique_ptr SmallStrainPerfectPlasticity::setup( + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, - const double * const h_n) + const Symmetric & s_n, + const History & h_n) { - SSPPTrialState * tss = new SSPPTrialState(); - make_trial_state(e_np1, e_n, T_np1, T_n, t_np1, T_n, - s_n, h_n, *tss); - return tss; + Symmetric ep_n = e_n - elastic_->S(T_n).dot(s_n); + Symmetric s_tr = s_n + elastic_->C(T_np1).dot(e_np1 - e_n); + return std::make_unique( + e_np1, ep_n, s_tr, elastic_->C(T_np1), -ys_->value(T_np1), + T_np1); } bool SmallStrainPerfectPlasticity::elastic_step( - const TrialState * ts, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - const double * const s_n, - const double * const h_n) + const TrialState * ts, const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, const Symmetric & s_n, + const History & h_n) { const SSPPTrialState * tss = static_cast(ts); double fv; - surface_->f(tss->s_tr, &(tss->ys), T_np1, fv); + surface_->f(tss->s_tr.data(), &(tss->ys), T_np1, fv); return fv <= 0.0; } void SmallStrainPerfectPlasticity::update_internal( - const double * const x, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n) + const double * const x, const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n) { - std::copy(x, x+6, s_np1); + s_np1.copy_data(x); } void SmallStrainPerfectPlasticity::strain_partial( - const TrialState * ts, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - const double * const s_np1, const double * const s_n, - const double * const h_np1, const double * const h_n, - double * const de) + const TrialState * ts, const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, + const Symmetric & s_np1, const Symmetric & s_n, + const History & h_np1, const History & h_n, double * de) { const SSPPTrialState * tss = static_cast(ts); std::fill(de, de+(6*nparams()), 0.0); for (size_t i = 0; i < 6; i++) { for (size_t j = 0; j < 6; j++) { - de[CINDEX(i,j,6)] = tss->C[CINDEX(i,j,6)]; + de[CINDEX(i,j,6)] = tss->C(i,j); } } - -} - -void SmallStrainPerfectPlasticity::work_and_energy( - const TrialState * ts, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double & u_np1, double u_n, - double & p_np1, double p_n) -{ - const SSPPTrialState * tss = static_cast(ts); - - // Plastic work calculation - double ds[6]; - add_vec(s_np1, s_n, 6, ds); - - double ee_np1[6]; - double S[36]; - elastic_->S(T_np1, S); - mat_vec(S, 6, s_np1, 6, ee_np1); - - double dp[6]; - for (size_t i = 0; i < 6; i++) dp[i] = e_np1[i] - ee_np1[i] - tss->ep_n[i]; - - p_np1 = p_n + dot_vec(ds, dp, 6) / 2.0; - - // Energy calculation (trapezoid rule) - double de[6]; - sub_vec(e_np1, e_n, 6, de); - u_np1 = u_n + dot_vec(ds, de, 6) / 2.0; - } size_t SmallStrainPerfectPlasticity::nparams() const @@ -595,7 +710,7 @@ size_t SmallStrainPerfectPlasticity::nparams() const void SmallStrainPerfectPlasticity::init_x(double * const x, TrialState * ts) { SSPPTrialState * tss = static_cast(ts); - std::copy(tss->s_tr, tss->s_tr+6, x); + std::copy(tss->s_tr.data(), tss->s_tr.data()+6, x); x[6] = 0.0; } @@ -604,45 +719,41 @@ void SmallStrainPerfectPlasticity::RJ( double * const J) { SSPPTrialState * tss = static_cast(ts); - const double * const s_np1 = x; + Symmetric s_np1(x); double dg = x[6]; // Common things double fv; - surface_->f(s_np1, &tss->ys, tss->T, fv); - - double df[6]; - surface_->df_ds(s_np1, &tss->ys, tss->T, df); + surface_->f(s_np1.data(), &tss->ys, tss->T, fv); + + Symmetric df; + surface_->df_ds(s_np1.data(), &tss->ys, tss->T, df.s()); - double ddf[36]; - surface_->df_dsds(s_np1, &tss->ys, tss->T, ddf); + SymSymR4 ddf; + surface_->df_dsds(s_np1.data(), &tss->ys, tss->T, ddf.s()); // R1 - double T[6]; - for (int i=0; i<6; i++) T[i] = tss->e_np1[i] - tss->ep_n[i] - df[i] * dg; - mat_vec(tss->C, 6, T, 6, R); - for (int i=0; i<6; i++) R[i] = s_np1[i] - R[i]; + Symmetric R1 = s_np1 - tss->C.dot(tss->e_np1 - tss->ep_n - df * dg); + for (size_t i = 0; i < 6; i++) R[i] = R1(i); // R2 R[6] = fv; // J11 - double TT[36]; - mat_mat(6, 6, 6, tss->C, ddf, TT); + SymSymR4 J11 = tss->C.dot(ddf)*dg + SymSymR4::id(); for (int i=0; i<6; i++) { for (int j=0; j<6; j++) { - J[CINDEX(i,j,7)] = TT[CINDEX(i,j,6)] * dg; + J[CINDEX(i,j,7)] = J11(i,j); } - J[CINDEX(i,i,7)] += 1.0; } // J12 - mat_vec(tss->C, 6, df, 6, T); - for (int i=0; i<6; i++) J[CINDEX(i,6,7)] = T[i]; + Symmetric J12 = tss->C.dot(df); + for (int i=0; i<6; i++) J[CINDEX(i,6,7)] = J12(i); // J21 - for (int i=0; i<6; i++) J[CINDEX(6,i,7)] = df[i]; + for (int i=0; i<6; i++) J[CINDEX(6,i,7)] = df(i); // J22 J[CINDEX(6,6,7)] = 0.0; @@ -654,40 +765,13 @@ double SmallStrainPerfectPlasticity::ys(double T) const return ys_->value(T); } -// Make this public for ease of testing -void SmallStrainPerfectPlasticity::make_trial_state( - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, const double * const h_n, - SSPPTrialState & ts) -{ - ts.ys = -ys_->value(T_np1); - ts.T = T_np1; - - std::copy(e_np1, e_np1+6, ts.e_np1); - - elastic_->C(T_np1, ts.C); - - double S_n[36]; - elastic_->S(T_n, S_n); - mat_vec(S_n, 6, s_n, 6, ts.ep_n); - for (size_t i = 0; i < 6; i++) ts.ep_n[i] = e_n[i] - ts.ep_n[i]; - - double de[6]; - sub_vec(e_np1, e_n, 6, de); - mat_vec(ts.C, 6, de, 6, ts.s_tr); - for (size_t i = 0; i < 6; i++) ts.s_tr[i] = s_n[i] + ts.s_tr[i]; - -} - // Implementation of small strain rate independent plasticity -// SmallStrainRateIndependentPlasticity::SmallStrainRateIndependentPlasticity( ParameterSet & params) : SubstepModel_sd(params), flow_(params.get_object_parameter("flow")) { - + cache_history_(); } std::string SmallStrainRateIndependentPlasticity::type() @@ -724,120 +808,82 @@ std::unique_ptr SmallStrainRateIndependentPlasticity::initialize(Par return neml::make_unique(params); } -size_t SmallStrainRateIndependentPlasticity::nhist() const +void SmallStrainRateIndependentPlasticity::populate_state(History & hist) const { - return flow_->nhist(); + flow_->set_variable_prefix(get_variable_prefix()); + flow_->populate_hist(hist); } -void SmallStrainRateIndependentPlasticity::init_hist(double * const hist) const +void SmallStrainRateIndependentPlasticity::init_state(History & hist) const { flow_->init_hist(hist); } -TrialState * SmallStrainRateIndependentPlasticity::setup( - const double * const e_np1, const double * const e_n, +std::unique_ptr SmallStrainRateIndependentPlasticity::setup( + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, - const double * const h_n) + const Symmetric & s_n, + const History & h_n) { - SSRIPTrialState * tss = new SSRIPTrialState(); - make_trial_state(e_np1, e_n, T_np1, T_n, t_np1, T_n, - s_n, h_n, *tss); - return tss; + Symmetric ep_tr = e_n - elastic_->S(T_n).dot(s_n); + SymSymR4 C = elastic_->C(T_np1); + Symmetric s_tr = C.dot(e_np1 - ep_tr); + + return std::make_unique(e_np1, ep_tr, s_tr, C, + h_n, T_np1); } bool SmallStrainRateIndependentPlasticity::elastic_step( - const TrialState * ts, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - const double * const s_n, - const double * const h_n) + const TrialState * ts, const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, const Symmetric & s_n, + const History & h_n) { const SSRIPTrialState * tss = static_cast(ts); double fv; - flow_->f(tss->s_tr, &tss->h_tr[0], T_np1, fv); + flow_->f(tss->s_tr.data(), tss->h_tr.rawptr(), T_np1, fv); return fv <= 0.0; } void SmallStrainRateIndependentPlasticity::update_internal( - const double * const x, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n) + const double * const x, const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n) { - std::copy(x, x+6, s_np1); - std::copy(x+6, x+6+nhist(), h_np1); + s_np1.copy_data(x); + h_np1.copy_data(x+6); } void SmallStrainRateIndependentPlasticity::strain_partial( - const TrialState * ts, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - const double * const s_np1, const double * const s_n, - const double * const h_np1, const double * const h_n, - double * const de) + const TrialState * ts, const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, + const Symmetric & s_np1, const Symmetric & s_n, + const History & h_np1, const History & h_n, double * de) { const SSRIPTrialState * tss = static_cast(ts); std::fill(de, de+(6*nparams()), 0.0); for (size_t i = 0; i < 6; i++) { for (size_t j = 0; j < 6; j++) { - de[CINDEX(i,j,6)] = tss->C[CINDEX(i,j,6)]; + de[CINDEX(i,j,6)] = tss->C(i,j); } } } -void SmallStrainRateIndependentPlasticity::work_and_energy( - const TrialState * ts, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double & u_np1, double u_n, - double & p_np1, double p_n) -{ - const SSRIPTrialState * tss = static_cast(ts); - - // Plastic work calculation - double ds[6]; - add_vec(s_np1, s_n, 6, ds); - - double ee_np1[6]; - double S[36]; - elastic_->S(T_np1, S); - mat_vec(S, 6, s_np1, 6, ee_np1); - - double dp[6]; - for (size_t i = 0; i < 6; i++) dp[i] = e_np1[i] - ee_np1[i] - tss->ep_tr[i]; - - p_np1 = p_n + dot_vec(ds, dp, 6) / 2.0; - - // Energy calculation (trapezoid rule) - double de[6]; - sub_vec(e_np1, e_n, 6, de); - u_np1 = u_n + dot_vec(ds, de, 6) / 2.0; - -} - size_t SmallStrainRateIndependentPlasticity::nparams() const { // My convention: plastic strain, history, consistency parameter - return 6 + flow_->nhist() + 1; + return 6 + nstate() + 1; } void SmallStrainRateIndependentPlasticity::init_x(double * const x, TrialState * ts) { SSRIPTrialState * tss = static_cast(ts); - std::copy(tss->s_tr, tss->s_tr+6, x); - std::copy(&tss->h_tr[0], &tss->h_tr[0]+flow_->nhist(), &x[6]); - x[6+flow_->nhist()] = 0.0; // consistency parameter + std::copy(tss->s_tr.data(), tss->s_tr.data()+6, x); + std::copy(tss->h_tr.rawptr(), tss->h_tr.rawptr()+nstate(), &x[6]); + x[6+nstate()] = 0.0; // consistency parameter } void SmallStrainRateIndependentPlasticity::RJ(const double * const x, @@ -847,33 +893,28 @@ void SmallStrainRateIndependentPlasticity::RJ(const double * const x, SSRIPTrialState * tss = static_cast(ts); // Again no idea why the compiler can't do this - int nh = flow_->nhist(); + int nh = nstate(); // Setup from current state - const double * const s_np1 = &x[0]; - const double * const alpha = &x[6]; - const double & dg = x[6+nh]; + Symmetric s_np1(x); + History alpha = gather_state_(&x[6]); + double dg = x[6+nh]; // Residual calculation - double g[6]; - flow_->g(s_np1, alpha, tss->T, g); - std::vector hv(nh); - double * h = &hv[0]; - flow_->h(s_np1, alpha, tss->T, h); + Symmetric g; + flow_->g(s_np1.data(), alpha.rawptr(), tss->T, g.s()); + History h = gather_blank_state_(); + flow_->h(s_np1.data(), alpha.rawptr(), tss->T, h.rawptr()); double f; - flow_->f(s_np1, alpha, tss->T, f); - - double R1[6]; - for (int i=0; i<6; i++) { - R1[i] = tss->e_np1[i] - tss->ep_tr[i] - g[i] * dg; - } - mat_vec(tss->C, 6, R1, 6, R); - for (int i=0; i<6; i++) { - R[i] = s_np1[i] - R[i]; - } + flow_->f(s_np1.data(), alpha.rawptr(), tss->T, f); + + // R1 + Symmetric R1 = s_np1 - tss->C.dot(tss->e_np1 - tss->ep_tr - g * dg); + for (size_t i = 0; i<6; i++) R[i] = R1(i); + // R2 for (int i=0; ih_tr[i] - h[i] * dg; + R[i+6] = alpha.rawptr()[i] - tss->h_tr.rawptr()[i] - h.rawptr()[i] * dg; } R[6+nh] = f; @@ -881,82 +922,69 @@ void SmallStrainRateIndependentPlasticity::RJ(const double * const x, int n = nparams(); // J11 - double gs[36]; - double J11[36]; - flow_->dg_ds(s_np1, alpha, tss->T, gs); - mat_mat(6, 6, 6, tss->C, gs, J11); - for (int i=0; i<36; i++) J11[i] = J11[i] * dg; - for (int i=0; i<6; i++) J11[CINDEX(i,i,6)] += 1.0; - + SymSymR4 gs, J11; + flow_->dg_ds(s_np1.data(), alpha.rawptr(), tss->T, gs.s()); + J11 = tss->C.dot(gs) * dg + SymSymR4::id(); for (int i=0; i<6; i++) { for (int j=0; j<6; j++) { - J[CINDEX(i,j,n)] = J11[CINDEX(i,j,6)]; + J[CINDEX(i,j,n)] = J11(i,j); } } - // J12 - std::vector gav(6*nh); - double * ga = &gav[0]; - std::vector J12v(6*nh); - double * J12 = &J12v[0]; - flow_->dg_da(s_np1, alpha, tss->T, ga); - mat_mat(6, nh, 6, tss->C, ga, J12); - - for (int i=0; i<6*nh; i++) J12[i] *= dg; + // J12 (transpose?) + History ga = gather_blank_state_().derivative(); + flow_->dg_da(s_np1.data(), alpha.rawptr(), tss->T, ga.rawptr()); + History J12 = ga.premultiply(tss->C) * dg; for (int i=0; i<6; i++) { for (int j=0; j < nh; j++) { - J[CINDEX(i,(j+6),n)] = J12[CINDEX(i,j,nh)]; + J[CINDEX(i,(j+6),n)] = J12.rawptr()[CINDEX(i,j,nh)]; } } // J13 - double J13[6]; - mat_vec(tss->C, 6, g, 6, J13); + Symmetric J13 = tss->C.dot(g); for (int i=0; i<6; i++) { - J[CINDEX(i,(6+nh),n)] = J13[i]; + J[CINDEX(i,(6+nh),n)] = J13.data()[i]; } - // J21 - std::vector J21v(nh*6); - double * J21 = &J21v[0]; - flow_->dh_ds(s_np1, alpha, tss->T, J21); - for (int i=0; i(); + flow_->dh_ds(s_np1.data(), alpha.rawptr(), tss->T, J21.rawptr()); + J21 *= dg; for (int i=0; i J22v(nh*nh); - double * J22 = &J22v[0]; - flow_->dh_da(s_np1, alpha, tss->T, J22); - for (int i=0; i(); + flow_->dh_da(s_np1.data(), alpha.rawptr(), tss->T, J22.rawptr()); + J22 *= dg; + for (int i=0; idf_ds(s_np1, alpha, tss->T, J31); + Symmetric J31; + flow_->df_ds(s_np1.data(), alpha.rawptr(), tss->T, J31.s()); for (int i=0; i<6; i++) { - J[CINDEX((6+nh), i, n)] = J31[i]; + J[CINDEX((6+nh), i, n)] = J31(i); } // J32 - std::vector J32v(nh); - double * J32 = &J32v[0]; - flow_->df_da(s_np1, alpha, tss->T, J32); + History J32 = gather_blank_state_(); + flow_->df_da(s_np1.data(), alpha.rawptr(), tss->T, J32.rawptr()); for (int i=0; i SmallStrainRateIndependentPlasti return elastic_; } -void SmallStrainRateIndependentPlasticity::make_trial_state( - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, const double * const h_n, - SSRIPTrialState & ts) -{ - // Save e_np1 - std::copy(e_np1, e_np1+6, ts.e_np1); - // ep_tr = ep_n - double S_n[36]; - double ee_n[6]; - elastic_->S(T_n, S_n); - - mat_vec(S_n, 6, s_n, 6, ee_n); - sub_vec(e_n, ee_n, 6, ts.ep_tr); - - ts.h_tr.resize(flow_->nhist()); - std::copy(h_n, h_n+nhist(), ts.h_tr.begin()); - // Calculate the trial stress - double ee[6]; - sub_vec(e_np1, ts.ep_tr, 6, ee); - elastic_->C(T_np1, ts.C); - - mat_vec(ts.C, 6, ee, 6, ts.s_tr); - // Store temp - ts.T = T_np1; -} - // Implement creep + plasticity // Implementation of small strain rate independent plasticity // @@ -1011,7 +1011,7 @@ SmallStrainCreepPlasticity::SmallStrainCreepPlasticity( verbose_(params.get_parameter("verbose")), linesearch_(params.get_parameter("linesearch")) { - + cache_history_(); } std::string SmallStrainCreepPlasticity::type() @@ -1046,72 +1046,67 @@ std::unique_ptr SmallStrainCreepPlasticity::initialize(ParameterSet return neml::make_unique(params); } -size_t SmallStrainCreepPlasticity::nhist() const +void SmallStrainCreepPlasticity::populate_state(History & hist) const { - // The elastic-plastic strain + the plastic model history - return plastic_->nhist() + 6; + hist.add(prefix("plastic_strain")); + plastic_->set_variable_prefix(get_variable_prefix()); + plastic_->populate_hist(hist); } -void SmallStrainCreepPlasticity::init_hist(double * const hist) const +void SmallStrainCreepPlasticity::init_state(History & hist) const { - std::fill(hist, hist+6, 0.0); - plastic_->init_hist(&hist[6]); + hist.get(prefix("plastic_strain")) = Symmetric::zero(); + plastic_->init_hist(hist); } -void SmallStrainCreepPlasticity::update_sd( - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, - double & u_np1, double u_n, - double & p_np1, double p_n) +void SmallStrainCreepPlasticity::update_sd_state( + const Symmetric & E_np1, const Symmetric & E_n, + double T_np1, double T_n, + double t_np1, double t_n, + Symmetric & S_np1, const Symmetric & S_n, + History & H_np1, const History & H_n, + SymSymR4 & AA_np1, + double & u_np1, double u_n, + double & p_np1, double p_n) { - + // Split out the history + History base_np1 = plastic_->gather_state_(H_np1.rawptr()); + History base_n = plastic_->gather_state_(H_n.rawptr()); + // Solve the system to get the update - SSCPTrialState ts; - make_trial_state(e_np1, e_n, T_np1, T_n, t_np1, t_n, s_n, h_n, ts); + std::unique_ptr ts = make_trial_state(E_np1, E_n, + T_np1, T_n, t_np1, t_n, S_n, + H_n); std::vector xv(nparams()); double * x = &xv[0]; - solve(this, x, &ts, {rtol_, atol_, miter_, verbose_, linesearch_}); + solve(this, x, ts.get(), {rtol_, atol_, miter_, verbose_, linesearch_}); // Store the ep strain - std::copy(x, x+6, h_np1); + H_np1.get(prefix("plastic_strain")) = Symmetric(x); // Do the plastic update to get the new history and stress - double A[36]; - plastic_->update_sd(x, ts.ep_strain, T_np1, T_n, - t_np1, t_n, s_np1, s_n, - &h_np1[6], &h_n[6], - A, u_np1, u_n, p_np1, p_n); + SymSymR4 A; + plastic_->update_sd_state(Symmetric(x), ts->ep_strain, + T_np1, T_n, + t_np1, t_n, S_np1, S_n, + base_np1, base_n, + A, u_np1, u_n, p_np1, p_n); // Do the creep update to get a tangent component - double creep_old[6]; - double creep_new[6]; - double B[36]; - for (int i=0; i<6; i++) { - creep_old[i] = e_n[i] - ts.ep_strain[i]; - } - creep_->update(s_np1, creep_new, creep_old, T_np1, T_n, + Symmetric creep_old = E_n - ts->ep_strain; + Symmetric creep_new; + SymSymR4 B; + creep_->update(S_np1.data(), creep_new, creep_old, T_np1, T_n, t_np1, t_n, B); // Form the relatively simple tangent - form_tangent_(A, B, A_np1); + AA_np1 = form_tangent_(A, B); // Energy calculation (trapezoid rule) - double de[6]; - double ds[6]; - sub_vec(e_np1, e_n, 6, de); - add_vec(s_np1, s_n, 6, ds); - u_np1 = u_n + dot_vec(ds, de, 6) / 2.0; - - // Extra dissipation from the creep material - double dec[6]; - sub_vec(creep_new, creep_old, 6, dec); - p_np1 += dot_vec(ds, dec, 6) / 2.0; - + auto [du, dp] = trapezoid_energy(E_np1, E_n, creep_new, creep_old, S_np1, S_n); + u_np1 = u_n + du; + p_np1 += dp; } size_t SmallStrainCreepPlasticity::nparams() const @@ -1125,7 +1120,7 @@ void SmallStrainCreepPlasticity::init_x(double * const x, TrialState * ts) SSCPTrialState * tss = static_cast(ts); // Start out at last step's value - std::copy(tss->ep_strain, tss->ep_strain + 6, x); + std::copy(tss->ep_strain.data(), tss->ep_strain.data() + 6, x); } void SmallStrainCreepPlasticity::RJ(const double * const x, TrialState * ts, @@ -1134,68 +1129,53 @@ void SmallStrainCreepPlasticity::RJ(const double * const x, TrialState * ts, SSCPTrialState * tss = static_cast(ts); // First update the elastic-plastic model - double s_np1[6]; - double A_np1[36]; - std::vector h_np1; - h_np1.resize(plastic_->nhist()); + Symmetric S_np1; + SymSymR4 A_np1; + History H_np1 = plastic_->gather_blank_state_(); + double u_np1, u_n; double p_np1, p_n; u_n = 0.0; p_n = 0.0; - double * hist = (h_np1.empty() ? nullptr : &h_np1[0]); - double * hist_tss = (tss->h_n.empty() ? nullptr : &(tss->h_n[0])); - - plastic_->update_sd(x, tss->ep_strain, tss->T_np1, tss->T_n, - tss->t_np1, tss->t_n, s_np1, tss->s_n, - hist, hist_tss, A_np1, - u_np1, u_n, p_np1, p_n); + Symmetric ep_np1(x); + plastic_->update_sd_state(ep_np1, tss->ep_strain, + tss->T_np1, tss->T_n, + tss->t_np1, tss->t_n, S_np1, + tss->s_n, + H_np1, tss->h_n, A_np1, + u_np1, u_n, p_np1, p_n); // Then update the creep strain - double creep_old[6]; - double creep_new[6]; - double B[36]; - for (int i=0; i<6; i++) { - creep_old[i] = tss->e_n[i] - tss->ep_strain[i]; - } - creep_->update(s_np1, creep_new, creep_old, tss->T_np1, tss->T_n, + Symmetric creep_old = tss->e_n - tss->ep_strain; + Symmetric creep_new; + SymSymR4 B; + creep_->update(S_np1, creep_new, creep_old, tss->T_np1, tss->T_n, tss->t_np1, tss->t_n, B); // Form the residual - for (int i=0; i<6; i++) { - R[i] = (x[i] + creep_new[i] - tss->e_np1[i]) * sf_; - } + Symmetric Rs(R); + Rs = (ep_np1 + creep_new - tss->e_np1) * sf_; // The Jacobian is a straightforward combination of the two derivatives - mat_mat(6, 6, 6, B, A_np1, J); - for (int i=0; i<6; i++) J[CINDEX(i,i,6)] += 1.0; - for (int i=0; i<36; i++) J[i] *= sf_; + SymSymR4 Js(J); + Js = (B.dot(A_np1) + SymSymR4::id()) * sf_; } -void SmallStrainCreepPlasticity::make_trial_state( - const double * const e_np1, const double * const e_n, +std::unique_ptr +SmallStrainCreepPlasticity::make_trial_state( + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, const double * const h_n, - SSCPTrialState & ts) + const Symmetric & s_n, const History & h_n) { - int nh = plastic_->nhist(); - ts.h_n.resize(nh); - - std::copy(e_np1, e_np1+6, ts.e_np1); - std::copy(e_n, e_n+6, ts.e_n); - std::copy(s_n, s_n+6, ts.s_n); - ts.T_n = T_n; - ts.T_np1 = T_np1; - ts.t_n = t_n; - ts.t_np1 = t_np1; - std::copy(h_n + 6, h_n + 6 + nh, ts.h_n.begin()); - - std::copy(h_n, h_n+6, ts.ep_strain); - + return std::make_unique( + h_n.get(prefix("plastic_strain")), + e_n, e_np1, s_n, T_n, T_np1, t_n, t_np1, + plastic_->gather_state_(h_n.rawptr())); } -void SmallStrainCreepPlasticity::form_tangent_( - double * const A, double * const B, double * const A_np1) +SymSymR4 SmallStrainCreepPlasticity::form_tangent_( + const SymSymR4 & A, const SymSymR4 & B) { // Okay, what we really want to do is // (A^-1 + B)^-1 @@ -1214,19 +1194,7 @@ void SmallStrainCreepPlasticity::form_tangent_( // // That said, it seems to work quite nicely. // - double C[36]; - mat_mat(6,6,6,A,B,C); - for (int i=0; i<6; i++) C[CINDEX(i,i,6)] += 1.0; - invert_mat(C, 6); - - double D[36]; - mat_mat(6,6,6,C,A,D); - mat_mat(6,6,6,B,D,C); - mat_mat(6,6,6,A,C,D); - - std::copy(A,A+36,A_np1); - for (int i=0; i<36; i++) A_np1[i] -= D[i]; - + return A - A.dot(B.dot((A.dot(B) + SymSymR4::id()).inverse().dot(A))); } void SmallStrainCreepPlasticity::set_elastic_model(std::shared_ptr emodel) @@ -1241,7 +1209,7 @@ GeneralIntegrator::GeneralIntegrator(ParameterSet & params) : rule_(params.get_object_parameter("rule")), skip_first_(params.get_parameter("skip_first_step")) { - + cache_history_(); } std::string GeneralIntegrator::type() @@ -1277,30 +1245,38 @@ std::unique_ptr GeneralIntegrator::initialize(ParameterSet & params) return neml::make_unique(params); } -TrialState * GeneralIntegrator::setup( - const double * const e_np1, const double * const e_n, +std::unique_ptr GeneralIntegrator::setup( + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - const double * const s_n, - const double * const h_n) + const Symmetric & s_n, + const History & h_n) { - GITrialState * tss = new GITrialState(); - make_trial_state(e_np1, e_n, T_np1, T_n, t_np1, t_n, - s_n, h_n, *tss); - return tss; + // Time increment + double dt = t_np1 - t_n; + + // Rates, avoiding divide by zero + double T_dot = 0.0; + Symmetric e_dot; + if (dt > 0.0) { + T_dot = (T_np1 - T_n) / dt; + e_dot = (e_np1 - e_n) / dt; + } + + // Default to elastic guess, unless the skip_first_ flag is true + Symmetric s_guess; + if ((t_n > 0.0) || (!skip_first_)) + s_guess = elastic_->C(T_np1).dot(e_np1 - e_n) + s_n; + + return std::make_unique(e_dot, s_n, s_guess, h_n, T_np1, + T_dot, dt); } bool GeneralIntegrator::elastic_step( - const TrialState * ts, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - const double * const s_n, - const double * const h_n) + const TrialState * ts, const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, const Symmetric & s_n, + const History & h_n) { - double de[6]; - sub_vec(e_np1, e_n, 6, de); - double dt = t_np1 - t_n; if (dt < std::numeric_limits::epsilon()) { @@ -1311,103 +1287,85 @@ bool GeneralIntegrator::elastic_step( } void GeneralIntegrator::update_internal( - const double * const x, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n) + const double * const x, const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, + Symmetric & s_np1, const Symmetric & s_n, + History & h_np1, const History & h_n) { - std::copy(x, x+6, s_np1); - std::copy(x+6, x+6+nhist(), h_np1); - + s_np1.copy_data(x); + h_np1.copy_data(x+6); } void GeneralIntegrator::strain_partial( - const TrialState * ts, - const double * const e_np1, const double * const e_n, - double T_np1, double T_n, - double t_np1, double t_n, - const double * const s_np1, const double * const s_n, - const double * const h_np1, const double * const h_n, - double * de) + const TrialState * ts, const Symmetric & e_np1, const Symmetric & e_n, + double T_np1, double T_n, double t_np1, double t_n, + const Symmetric & s_np1, const Symmetric & s_n, + const History & h_np1, const History & h_n, double * de) { const GITrialState * tss = static_cast(ts); - double * estress = new double [6*6]; - - rule_->ds_de(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot, estress); + SymSymR4 estress = rule_->ds_de(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot); for (size_t i = 0; i < 6; i++) { for (size_t j = 0; j < 6; j++) { - de[CINDEX(i,j,6)] = estress[CINDEX(i,j,6)]; + de[CINDEX(i,j,6)] = estress(i,j); } } - - delete [] estress; - - double * ehist = new double [6*nhist()]; - - rule_->da_de(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot, ehist); - for (size_t i = 0; i < nhist(); i++) { + + History ehist = rule_->da_de(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot); + for (size_t i = 0; i < nstate(); i++) { for (size_t j = 0; j < 6; j++) { - de[CINDEX((i+6),j,6)] = ehist[CINDEX(i,j,6)]; + de[CINDEX((i+6),j,6)] = ehist.rawptr()[CINDEX(i,j,6)]; } } - - delete [] ehist; - } void GeneralIntegrator::work_and_energy( const TrialState * ts, - const double * const e_np1, const double * const e_n, + const Symmetric & e_np1, const Symmetric & e_n, double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, + const Symmetric & s_np1, const Symmetric & s_n, + const History & h_np1, const History & h_n, double & u_np1, double u_n, double & p_np1, double p_n) { const GITrialState * tss = static_cast(ts); - // Energy calculation (trapezoid rule) - double de[6]; - double ds[6]; - sub_vec(e_np1, e_n, 6, de); - add_vec(s_np1, s_n, 6, ds); - for (int i=0; i<6; i++) ds[i] /= 2.0; - u_np1 = u_n + dot_vec(ds, de, 6); - - // Need a special call - double p_dot_np1; - rule_->work_rate(s_np1, h_np1, tss->e_dot, T_np1, tss->Tdot, p_dot_np1); - double p_dot_n; - rule_->work_rate(s_n, h_n, tss->e_dot, T_n, tss->Tdot, p_dot_n); - p_np1 = p_n + (p_dot_np1 + p_dot_n)/2.0 * tss->dt; + // Energy + Symmetric de = e_np1 - e_n; + Symmetric ds = s_np1 - s_n; + u_np1 = u_n + ds.contract(de) / 2.0; + // Dissipation needs a special call + double p_dot_np1 = rule_->work_rate(s_np1, h_np1, tss->e_dot, + T_np1, tss->Tdot); + double p_dot_n = rule_->work_rate(s_n, h_n, tss->e_dot, + T_n, tss->Tdot); + p_np1 = p_n + (p_dot_np1 + p_dot_n)/2.0 * tss->dt; } -size_t GeneralIntegrator::nhist() const +void GeneralIntegrator::populate_state(History & hist) const { - return rule_->nhist(); + rule_->set_variable_prefix(get_variable_prefix()); + rule_->populate_hist(hist); } -void GeneralIntegrator::init_hist(double * const hist) const +void GeneralIntegrator::init_state(History & hist) const { rule_->init_hist(hist); } size_t GeneralIntegrator::nparams() const { - return 6 + nhist(); + return 6 + nstate(); } void GeneralIntegrator::init_x(double * const x, TrialState * ts) { GITrialState * tss = static_cast(ts); - std::copy(tss->s_guess, tss->s_guess+6, x); - std::copy(tss->h_n.begin(), tss->h_n.end(), &x[6]); + std::copy(tss->s_guess.data(), tss->s_guess.data()+6, x); + std::copy(tss->h_n.rawptr(), tss->h_n.rawptr() + nstate(), &x[6]); rule_->override_guess(x); } @@ -1418,114 +1376,65 @@ void GeneralIntegrator::RJ(const double * const x, TrialState * ts, GITrialState * tss = static_cast(ts); // Setup - const double * s_np1 = x; - const double * const h_np1 = &x[6]; + Symmetric s_np1(x); + History h_np1 = gather_state_(x+6); // Helps with vectorization // Really as I declared both const this shouldn't be necessary but hey // I don't design optimizing compilers for a living - int nhist = this->nhist(); + int nstate = this->nstate(); int nparams = this->nparams(); // Residual calculation - rule_->s(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot, R); + Symmetric fr = rule_->s(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot); + Symmetric R1 = s_np1 - tss->s_n - fr * tss->dt; for (int i=0; i<6; i++) { - R[i] = s_np1[i] - tss->s_n[i] - R[i] * tss->dt; + R[i] = R1(i); } - rule_->a(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot, &R[6]); - for (int i=0; ih_n[i] - R[i+6] * tss->dt; + History h_rate = rule_->a(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot); + for (int i=0; ih_n.rawptr()[i] - h_rate.rawptr()[i] * tss->dt; } // Jacobian calculation - double J11[36]; - rule_->ds_ds(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot, J11); - for (int i=0; i<36; i++) J11[i] *= tss->dt; - for (int i=0; i<6; i++) J11[CINDEX(i,i,6)] -= 1.0; + SymSymR4 J11 = rule_->ds_ds(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot); + J11 = J11 * tss->dt - SymSymR4::id(); for (int i=0; i<6; i++) { for (int j=0; j<6; j++) { - J[CINDEX(i,j,nparams)] = -J11[CINDEX(i,j,6)]; + J[CINDEX(i,j,nparams)] = -J11.data()[CINDEX(i,j,6)]; } } - std::vector J12v(6*nhist); - double * J12 = &J12v[0]; - rule_->ds_da(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot, J12); + // Transpose? + History J12 = rule_->ds_da(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot); for (int i=0; i<6; i++) { - for (int j=0; jdt; + for (int j=0; jdt; } } - std::vector J21v(nhist*6); - double * J21 = &J21v[0]; - rule_->da_ds(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot, J21); - for (int i=0; ida_ds(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot); + for (int i=0; idt; + J[CINDEX((i+6),j,nparams)] = -J21.rawptr()[CINDEX(i,j,6)] * tss->dt; } } - std::vector J22v(nhist*nhist); - double * J22 = &J22v[0]; - rule_->da_da(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot, J22); + History J22 = rule_->da_da(s_np1, h_np1, tss->e_dot, tss->T, tss->Tdot); // More vectorization double dt = tss->dt; - for (int i=0; i 0.0) { - ts.Tdot = (T_np1 - T_n) / ts.dt; - for (int i=0; i<6; i++) { - ts.e_dot[i] = (e_np1[i] - e_n[i]) / ts.dt; - } - } - else { - ts.Tdot = 0.0; - std::fill(ts.e_dot, ts.e_dot+6, 0.0); - } - - // Last stress - std::copy(s_n, s_n+6, ts.s_n); - - // Last history - ts.h_n.resize(nhist()); - std::copy(h_n, h_n+nhist(), ts.h_n.begin()); - - // Elastic guess - double C[36]; - elastic_->C(T_np1, C); - double de[6]; - sub_vec(e_np1, e_n, 6, de); - mat_vec(C, 6, de, 6, ts.s_guess); - add_vec(ts.s_guess, s_n, 6, ts.s_guess); - - // Special logic... - if ((t_n == 0.0) && (skip_first_)) - std::copy(s_n, s_n+6, ts.s_guess); - -} - void GeneralIntegrator::set_elastic_model(std::shared_ptr emodel) { elastic_ = emodel; @@ -1542,7 +1451,7 @@ KMRegimeModel::KMRegimeModel(ParameterSet & params) : b_(params.get_parameter("b")), eps0_(params.get_parameter("eps0")) { - + cache_history_(); } std::string KMRegimeModel::type() @@ -1574,54 +1483,53 @@ std::unique_ptr KMRegimeModel::initialize(ParameterSet & params) return neml::make_unique(params); } -void KMRegimeModel::update_sd( - const double * const e_np1, const double * const e_n, +void KMRegimeModel::update_sd_state( + const Symmetric & E_np1, const Symmetric & E_n, double T_np1, double T_n, double t_np1, double t_n, - double * const s_np1, const double * const s_n, - double * const h_np1, const double * const h_n, - double * const A_np1, + Symmetric & S_np1, const Symmetric & S_n, + History & H_np1, const History & H_n, + SymSymR4 & AA_np1, double & u_np1, double u_n, double & p_np1, double p_n) { // Calculate activation energy - double g = activation_energy_(e_np1, e_n, T_np1, t_np1, t_n); + double g = activation_energy_(E_np1, E_n, T_np1, t_np1, t_n); // Note this relies on everything being sorted. You probably want to // error check at some point for (size_t i=0; iupdate_sd(e_np1, e_n, T_np1, T_n, t_np1, t_n, - s_np1, s_n, h_np1, h_n, A_np1, u_np1, u_n, + return models_[i]->update_sd_state(E_np1, E_n, T_np1, T_n, t_np1, t_n, + S_np1, S_n, H_np1, H_n, AA_np1, u_np1, u_n, p_np1, p_n); } } - return models_.back()->update_sd(e_np1, e_n, T_np1, T_n, t_np1, t_n, - s_np1, s_n, h_np1, h_n, A_np1, u_np1, u_n, + return models_.back()->update_sd_state(E_np1, E_n, T_np1, T_n, t_np1, t_n, + S_np1, S_n, H_np1, H_n, AA_np1, u_np1, u_n, p_np1, p_n); } -size_t KMRegimeModel::nhist() const +void KMRegimeModel::populate_state(History & hist) const { - return models_[0]->nhist(); + for (auto model : models_) + model->set_variable_prefix(get_variable_prefix()); + + return models_[0]->populate_hist(hist); } -void KMRegimeModel::init_hist(double * const hist) const +void KMRegimeModel::init_state(History & hist) const { return models_[0]->init_hist(hist); } -double KMRegimeModel::activation_energy_(const double * const e_np1, - const double * const e_n, +double KMRegimeModel::activation_energy_(const Symmetric & e_np1, + const Symmetric & e_n, double T_np1, double t_np1, double t_n) { - double dt = t_np1 - t_n; - - double de[6]; - sub_vec(e_np1, e_n, 6, de); - for (int i=0; i<6; i++) de[i] /= dt; - double rate = sqrt(2.0/3.0) * norm2_vec(de, 6); + Symmetric de = (e_np1 - e_n) / (t_np1 - t_n); + double rate = sqrt(2.0/3.0) * de.norm(); double mu = elastic_->G(T_np1); return kboltz_ * T_np1 / (mu* pow(b_, 3.0)) * log(eps0_ / rate); @@ -1635,4 +1543,19 @@ void KMRegimeModel::set_elastic_model(std::shared_ptr emodel } } +std::tuple trapezoid_energy( + const Symmetric & e_np1, const Symmetric & e_n, + const Symmetric & ep_np1, const Symmetric & ep_n, + const Symmetric & s_np1, const Symmetric & s_n) +{ + Symmetric de = e_np1 - e_n; + Symmetric dp = ep_np1 - ep_n; + Symmetric ds = s_np1 + s_n; + + double du = ds.contract(de)/2.0; + double dw = ds.contract(dp)/2.0; + + return std::tie(du,dw); +} + } // namespace neml diff --git a/src/models_wrap.cxx b/src/models_wrap.cxx index 9a1e8c51..b864059c 100644 --- a/src/models_wrap.cxx +++ b/src/models_wrap.cxx @@ -17,25 +17,8 @@ PYBIND11_MODULE(models, m) { m.doc() = "Base class for all material models."; - py::class_>(m, "NEMLModel") + py::class_>(m, "NEMLModel") .def("save", &NEMLModel::save) - .def_property_readonly("nstore", &NEMLModel::nstore, "Number of variables the program needs to store.") - .def("init_store", - [](NEMLModel & m) -> py::array_t - { - auto h = alloc_vec(m.nstore()); - m.init_store(arr2ptr(h)); - return h; - }, "Initialize stored variables.") - - .def_property_readonly("nhist", &NEMLModel::nhist, "Number of actual history variables.") - .def("init_hist", - [](NEMLModel & m) -> py::array_t - { - auto h = alloc_vec(m.nhist()); - m.init_hist(arr2ptr(h)); - return h; - }, "Initialize history variables.") .def("update_sd", [](NEMLModel & m, py::array_t e_np1, py::array_t e_n, double T_np1, double T_n, double t_np1, double t_n, py::array_t s_n, py::array_t h_n, double u_n, double p_n) -> std::tuple, py::array_t, py::array_t, double, double> { @@ -89,6 +72,16 @@ PYBIND11_MODULE(models, m) { py::class_>(m, "SubstepModel_sd") + .def("make_trial_state", + [](SubstepModel_sd & m, py::array_t e_np1, py::array_t e_n, double T_np1, double T_n, double t_np1, double t_n, py::array_t s_n, py::array_t h_n) -> std::unique_ptr + { + return m.setup(arr2ptr(e_np1), + arr2ptr(e_n), + T_np1, T_n, + t_np1, t_n, + arr2ptr(s_n), + arr2ptr(h_n)); + }, "Setup trial state for solve.") ; py::class_>(m, "SmallStrainElasticity") @@ -122,20 +115,6 @@ PYBIND11_MODULE(models, m) { })) .def("ys", &SmallStrainPerfectPlasticity::ys) - - .def("make_trial_state", - [](SmallStrainPerfectPlasticity & m, py::array_t e_np1, py::array_t e_n, double T_np1, double T_n, double t_np1, double t_n, py::array_t s_n, py::array_t h_n) -> std::unique_ptr - { - std::unique_ptr ts(new SSPPTrialState); - m.make_trial_state(arr2ptr(e_np1), - arr2ptr(e_n), - T_np1, T_n, - t_np1, t_n, - arr2ptr(s_n), - arr2ptr(h_n), - *ts); - return ts; - }, "Setup trial state for solve.") ; py::class_>(m, "SmallStrainRateIndependentPlasticity") @@ -145,20 +124,6 @@ PYBIND11_MODULE(models, m) { return create_object_python(args, kwargs, {"elastic", "flow"}); })) - - .def("make_trial_state", - [](SmallStrainRateIndependentPlasticity & m, py::array_t e_np1, py::array_t e_n, double T_np1, double T_n, double t_np1, double t_n, py::array_t s_n, py::array_t h_n) -> std::unique_ptr - { - std::unique_ptr ts(new SSRIPTrialState); - m.make_trial_state(arr2ptr(e_np1), - arr2ptr(e_n), - T_np1, T_n, - t_np1, t_n, - arr2ptr(s_n), - arr2ptr(h_n), - *ts); - return ts; - }, "Setup trial state for solve.") ; py::class_>(m, "SmallStrainCreepPlasticity") @@ -173,20 +138,15 @@ PYBIND11_MODULE(models, m) { .def("make_trial_state", [](SmallStrainCreepPlasticity & m, py::array_t e_np1, py::array_t e_n, double T_np1, double T_n, double t_np1, double t_n, py::array_t s_n, py::array_t h_n) -> std::unique_ptr { - std::unique_ptr ts(new SSCPTrialState); - m.make_trial_state(arr2ptr(e_np1), - arr2ptr(e_n), - T_np1, T_n, - t_np1, t_n, - arr2ptr(s_n), - arr2ptr(h_n), - *ts); - return ts; + return m.make_trial_state(Symmetric(arr2ptr(e_np1)), + Symmetric(arr2ptr(e_n)), + T_np1, T_n, + t_np1, t_n, + Symmetric(arr2ptr(s_n)), + m.gather_state_(arr2ptr(h_n))); }, "Setup trial state for solve.") ; - - py::class_>(m, "GeneralIntegrator") PICKLEABLE(GeneralIntegrator) .def(py::init([](py::args args, py::kwargs kwargs) @@ -194,20 +154,6 @@ PYBIND11_MODULE(models, m) { return create_object_python(args, kwargs, {"elastic", "rule"}); })) - - .def("make_trial_state", - [](GeneralIntegrator & m, py::array_t e_np1, py::array_t e_n, double T_np1, double T_n, double t_np1, double t_n, py::array_t s_n, py::array_t h_n) -> std::unique_ptr - { - std::unique_ptr ts(new GITrialState); - m.make_trial_state(arr2ptr(e_np1), - arr2ptr(e_n), - T_np1, T_n, - t_np1, t_n, - arr2ptr(s_n), - arr2ptr(h_n), - *ts); - return ts; - }, "Setup trial state for solve.") ; py::class_>(m, "KMRegimeModel") diff --git a/src/ri_flow.cxx b/src/ri_flow.cxx index e5136a00..3fb616f5 100644 --- a/src/ri_flow.cxx +++ b/src/ri_flow.cxx @@ -5,7 +5,7 @@ namespace neml { RateIndependentFlowRule::RateIndependentFlowRule(ParameterSet & params) : - NEMLObject(params) + HistoryNEMLObject(params) { } @@ -39,18 +39,18 @@ std::unique_ptr RateIndependentAssociativeFlow::initialize(Parameter return neml::make_unique(params); } -size_t RateIndependentAssociativeFlow::nhist() const -{ - return hardening_->nhist(); -} - -void RateIndependentAssociativeFlow::init_hist(double * const h) const +void RateIndependentAssociativeFlow::populate_hist(History & hist) const { if (hardening_->nhist() != surface_->nhist()) { throw NEMLError("Hardening model and flow surface are not compatible"); } + hardening_->set_variable_prefix(get_variable_prefix()); + hardening_->populate_hist(hist); +} - hardening_->init_hist(h); +void RateIndependentAssociativeFlow::init_hist(History & hist) const +{ + hardening_->init_hist(hist); } void RateIndependentAssociativeFlow::f(const double* const s, @@ -209,19 +209,18 @@ std::unique_ptr RateIndependentNonAssociativeHardening::initialize(P return neml::make_unique(params); } -size_t RateIndependentNonAssociativeHardening::nhist() const -{ - return hardening_->nhist(); -} - -void RateIndependentNonAssociativeHardening::init_hist(double * const h) const +void RateIndependentNonAssociativeHardening::populate_hist(History & hist) const { if (hardening_->ninter() != surface_->nhist()) { throw NEMLError("Hardening model and flow surface are not compatible"); } + hardening_->set_variable_prefix(get_variable_prefix()); + hardening_->populate_hist(hist); +} - hardening_->init_hist(h); - +void RateIndependentNonAssociativeHardening::init_hist(History & hist) const +{ + hardening_->init_hist(hist); } void RateIndependentNonAssociativeHardening::f(const double* const s, diff --git a/src/ri_flow_wrap.cxx b/src/ri_flow_wrap.cxx index 8993ce5e..abb04cbb 100644 --- a/src/ri_flow_wrap.cxx +++ b/src/ri_flow_wrap.cxx @@ -15,16 +15,7 @@ PYBIND11_MODULE(ri_flow, m) { m.doc() = "Rate independent flow models."; - py::class_>(m, "RateIndenpendentFlowRule") - .def_property_readonly("nhist", &RateIndependentFlowRule::nhist, "Number of history variables.") - .def("init_hist", - [](RateIndependentFlowRule & m) -> py::array_t - { - auto h = alloc_vec(m.nhist()); - m.init_hist(arr2ptr(h)); - return h; - }, "Initialize history variables.") - + py::class_>(m, "RateIndenpendentFlowRule") .def("f", [](RateIndependentFlowRule & m, py::array_t s, py::array_t alpha, double T) -> double { diff --git a/src/visco_flow.cxx b/src/visco_flow.cxx index 2933151d..bc1a5584 100644 --- a/src/visco_flow.cxx +++ b/src/visco_flow.cxx @@ -8,7 +8,7 @@ namespace neml { ViscoPlasticFlowRule::ViscoPlasticFlowRule(ParameterSet & params) : - NEMLObject(params) + HistoryNEMLObject(params) { } @@ -115,6 +115,9 @@ SuperimposedViscoPlasticFlowRule::SuperimposedViscoPlasticFlowRule(ParameterSet for (size_t i = 1; i <= rules_.size(); i++) { offsets_[i] = offsets_[i-1] + rules_[i-1]->nhist(); } + + for (size_t i = 0; i < nmodels(); i++) + rules_[i]->set_variable_prefix("model"+std::to_string(i)+"_"); } std::string SuperimposedViscoPlasticFlowRule::type() @@ -142,15 +145,16 @@ size_t SuperimposedViscoPlasticFlowRule::nmodels() const return rules_.size(); } -size_t SuperimposedViscoPlasticFlowRule::nhist() const +void SuperimposedViscoPlasticFlowRule::populate_hist(History & hist) const { - return offsets_[nmodels()]; + for (size_t i = 0; i < nmodels(); i++) + rules_[i]->populate_hist(hist); } -void SuperimposedViscoPlasticFlowRule::init_hist(double * const h) const +void SuperimposedViscoPlasticFlowRule::init_hist(History & hist) const { for (size_t i = 0; i < nmodels(); i++) - rules_[i]->init_hist(model_history_(h, i)); + rules_[i]->init_hist(hist); } void SuperimposedViscoPlasticFlowRule::y(const double* const s, @@ -699,18 +703,21 @@ std::unique_ptr PerzynaFlowRule::initialize(ParameterSet & params) return neml::make_unique(params); } -size_t PerzynaFlowRule::nhist() const -{ - return hardening_->nhist(); -} - -void PerzynaFlowRule::init_hist(double * const h) const +void PerzynaFlowRule::populate_hist(History & hist) const { if (surface_->nhist() != hardening_->nhist()) { throw NEMLError("Hardening model and flow surface are not compatible"); } - hardening_->init_hist(h); + + // We want to make sure the variable prefix remains the same + hardening_->set_variable_prefix(get_variable_prefix()); + + hardening_->populate_hist(hist); +} +void PerzynaFlowRule::init_hist(History & hist) const +{ + hardening_->init_hist(hist); } // Rate rule @@ -894,12 +901,12 @@ std::unique_ptr LinearViscousFlow::initialize(ParameterSet & params) return neml::make_unique(params); } -size_t LinearViscousFlow::nhist() const +void LinearViscousFlow::init_hist(History & h) const { - return 0; + return; } -void LinearViscousFlow::init_hist(double * const h) const +void LinearViscousFlow::populate_hist(History & h) const { return; } @@ -1106,17 +1113,21 @@ std::unique_ptr ChabocheFlowRule::initialize(ParameterSet & params) return neml::make_unique(params); } -size_t ChabocheFlowRule::nhist() const -{ - return hardening_->nhist(); -} - -void ChabocheFlowRule::init_hist(double * const h) const +void ChabocheFlowRule::populate_hist(History & hist) const { if (surface_->nhist() != hardening_->ninter()) { throw NEMLError("Hardening model and flow surface are not compatible"); } - hardening_->init_hist(h); + + // Make sure the variable prefix stays the same + hardening_->set_variable_prefix(get_variable_prefix()); + + hardening_->populate_hist(hist); +} + +void ChabocheFlowRule::init_hist(History & hist) const +{ + hardening_->init_hist(hist); } // Rate rule @@ -1321,30 +1332,25 @@ std::unique_ptr YaguchiGr91FlowRule::initialize(ParameterSet & param } -size_t YaguchiGr91FlowRule::nhist() const +void YaguchiGr91FlowRule::populate_hist(History & hist) const { // Order: // 0-5 X1 // 6-11 X2 // 12 Q // 13 sa - return 14; + hist.add(prefix("X1")); + hist.add(prefix("X2")); + hist.add(prefix("Q")); + hist.add(prefix("sa")); } -void YaguchiGr91FlowRule::init_hist(double * const h) const +void YaguchiGr91FlowRule::init_hist(History & hist) const { - // This also hardcoded from the paper - - // Xs - std::fill(h, h+12, 0.0); - - // Q - h[12] = 0.0; - - // sa - h[13] = 0.0; - - + hist.get(prefix("X1")) = Symmetric::zero(); + hist.get(prefix("X2")) = Symmetric::zero(); + hist.get(prefix("Q")) = 0.0; + hist.get(prefix("sa")) = 0.0; } // Rate rule @@ -1368,7 +1374,6 @@ void YaguchiGr91FlowRule::y(const double* const s, const double* const alpha, do else { yv = 0.0; } - } void YaguchiGr91FlowRule::dy_ds(const double* const s, const double* const alpha, double T, diff --git a/src/visco_flow_wrap.cxx b/src/visco_flow_wrap.cxx index 2f172e47..b17184eb 100644 --- a/src/visco_flow_wrap.cxx +++ b/src/visco_flow_wrap.cxx @@ -14,16 +14,7 @@ PYBIND11_MODULE(visco_flow, m) { m.doc() = "Viscoplastic flow models."; - py::class_>(m, "ViscoPlasticFlowRule") - .def_property_readonly("nhist", &ViscoPlasticFlowRule::nhist, "Number of history variables.") - .def("init_hist", - [](ViscoPlasticFlowRule & m) -> py::array_t - { - auto h = alloc_vec(m.nhist()); - m.init_hist(arr2ptr(h)); - return h; - }, "Initialize history variables.") - + py::class_>(m, "ViscoPlasticFlowRule") .def("y", [](ViscoPlasticFlowRule & m, py::array_t s, py::array_t alpha, double T) -> double { diff --git a/src/walker.cxx b/src/walker.cxx index 5bcd7699..ad1588f9 100644 --- a/src/walker.cxx +++ b/src/walker.cxx @@ -9,7 +9,7 @@ WalkerKremplSwitchRule::WalkerKremplSwitchRule(ParameterSet & params) : lambda_(params.get_object_parameter("lambda")), eps0_(params.get_parameter("eps_ref")) { - + cache_history_(); } std::string WalkerKremplSwitchRule::type() @@ -35,293 +35,214 @@ std::unique_ptr WalkerKremplSwitchRule::initialize(ParameterSet & pa } -size_t WalkerKremplSwitchRule::nhist() const +void WalkerKremplSwitchRule::populate_hist(History & hist) const { - return flow_->nhist(); + flow_->set_variable_prefix(get_variable_prefix()); + return flow_->populate_hist(hist); } -void WalkerKremplSwitchRule::init_hist(double * const h) +void WalkerKremplSwitchRule::init_hist(History & hist) const { - return flow_->init_hist(h); + return flow_->init_hist(hist); } -void WalkerKremplSwitchRule::s(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const sdot) +Symmetric WalkerKremplSwitchRule::s(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { - double erate[6]; - std::copy(edot, edot+6, erate); + Symmetric erate = edot; - double temp[6]; + Symmetric dir; double yv; - flow_->g(s, alpha, T, temp); - flow_->y(s, alpha, T, yv); + flow_->g(s.data(), alpha.rawptr(), T, dir.s()); + flow_->y(s.data(), alpha.rawptr(), T, yv); - double kap; - kappa(edot, T, kap); - - for (int i=0; i<6; i++) { - erate[i] -= yv * kap * temp[i]; - } + double kap = kappa(edot, T); - double C[36]; - elastic_->C(T, C); + erate -= yv * kap * dir; - mat_vec(C, 6, erate, 6, sdot); + return elastic_->C(T).dot(erate); } -void WalkerKremplSwitchRule::ds_ds(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot) +SymSymR4 WalkerKremplSwitchRule::ds_ds(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { double yv; - flow_->y(s, alpha, T, yv); + flow_->y(s.data(), alpha.rawptr(), T, yv); - double kap; - kappa(edot, T, kap); + double kap = kappa(edot, T); - double work[36]; - flow_->dg_ds(s, alpha, T, work); - for (int i=0; i<36; i++) { - work[i] *= -yv * kap; - } + SymSymR4 work; + flow_->dg_ds(s.data(), alpha.rawptr(), T, work.s()); + work *= -yv * kap; - double t1[6]; - flow_->g(s, alpha, T, t1); - double t2[6]; - flow_->dy_ds(s, alpha, T, t2); - for (size_t i = 0; i < 6; i++) t2[i] *= kap; - outer_update_minus(t1, 6, t2, 6, work); + Symmetric t1; + flow_->g(s.data(), alpha.rawptr(), T, t1.s()); + Symmetric t2; + flow_->dy_ds(s.data(), alpha.rawptr(), T, t2.s()); + t2 *= kap; + work -= douter(t1, t2); - double t3[36]; - elastic_->C(T, t3); - - mat_mat(6,6,6, t3, work, d_sdot); + return elastic_->C(T).dot(work); } -void WalkerKremplSwitchRule::ds_da(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot) +History WalkerKremplSwitchRule::ds_da(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { double yv; - flow_->y(s, alpha, T, yv); + flow_->y(s.data(), alpha.rawptr(), T, yv); - double kap; - kappa(edot, T, kap); - - int sz = 6 * nhist(); + double kap = kappa(edot, T); + + History work = gather_blank_history_().derivative(); + flow_->dg_da(s.data(), alpha.rawptr(), T, work.rawptr()); + work *= -yv * kap; + + Symmetric t1; + flow_->g(s.data(), alpha.rawptr(), T, t1.s()); + History t2 = gather_blank_history_(); + flow_->dy_da(s.data(), alpha.rawptr(), T, t2.rawptr()); + t2 *= kap; + outer_update_minus(t1.data(), 6, t2.rawptr(), nhist(), work.rawptr()); - std::vector workv(sz); - double * work = &workv[0]; - flow_->dg_da(s, alpha, T, work); - for (int i=0; ig(s, alpha, T, t1); - std::vector t2v(nhist()); - double * t2 = &t2v[0]; - flow_->dy_da(s, alpha, T, t2); - for (size_t i = 0; i < nhist(); i++) t2[i] *= kap; - outer_update_minus(t1, 6, t2, nhist(), work); - - double C[36]; - elastic_->C(T, C); - - mat_mat(6, nhist(), 6, C, work, d_sdot); + return work.premultiply(elastic_->C(T)); } -void WalkerKremplSwitchRule::ds_de(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_sdot) +SymSymR4 WalkerKremplSwitchRule::ds_de(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { - double work[36]; - double yv; - flow_->y(s, alpha, T, yv); - - double dkap[6]; - dkappa(edot, T, dkap); - - double g[6]; - flow_->g(s, alpha, T, g); - - for (size_t i = 0; i < 6; i++) g[i] *= yv; - - std::fill(work, work+36, 0.0); - for (size_t i = 0; i < 6; i++) work[CINDEX(i,i,6)] = 1.0; - outer_update_minus(g, 6, dkap, 6, work); - - double C[36]; - elastic_->C(T, C); + flow_->y(s.data(), alpha.rawptr(), T, yv); + + Symmetric dkap = dkappa(edot, T); - mat_mat(6, 6, 6, C, work, d_sdot); + Symmetric g; + flow_->g(s.data(), alpha.rawptr(), T, g.s()); + g *= yv; + + return elastic_->C(T).dot(SymSymR4::id() - douter(g, dkap)); } -void WalkerKremplSwitchRule::a(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const adot) +History WalkerKremplSwitchRule::a(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { double dg; - flow_->y(s, alpha, T, dg); + flow_->y(s.data(), alpha.rawptr(), T, dg); - double kap; - kappa(edot, T, kap); - - flow_->h(s, alpha, T, adot); - for (size_t i=0; ih(s.data(), alpha.rawptr(), T, adot.rawptr()); + adot *= dg * kap; - std::vector tempv(nhist()); - double * temp = &tempv[0]; - flow_->h_temp(s, alpha, T, temp); - for (size_t i=0; ih_temp(s.data(), alpha.rawptr(), T, temp.rawptr()); + adot += temp * Tdot; + flow_->h_time(s.data(), alpha.rawptr(), T, temp.rawptr()); - flow_->h_time(s, alpha, T, temp); - for (size_t i=0; iy(s, alpha, T, dg); - - double kap; - kappa(edot, T, kap); + flow_->y(s.data(), alpha.rawptr(), T, dg); - int sz = nhist() * 6; + double kap = kappa(edot, T); - flow_->dh_ds(s, alpha, T, d_adot); - for (int i=0; i t1v(nhist()); - double * t1 = &t1v[0]; - flow_->h(s, alpha, T, t1); + History d_adot = gather_blank_history_().derivative(); + flow_->dh_ds(s.data(), alpha.rawptr(), T, d_adot.rawptr()); + d_adot *= dg * kap; + + History t1 = gather_blank_history_(); + flow_->h(s.data(), alpha.rawptr(), T, t1.rawptr()); - double t2[6]; - flow_->dy_ds(s, alpha, T, t2); - for (size_t i = 0; i < 6; i++) t2[i] *= kap; + Symmetric t2; + flow_->dy_ds(s.data(), alpha.rawptr(), T, t2.s()); + t2 *= kap; - outer_update(t1, nhist(), t2, 6, d_adot); + outer_update(t1.rawptr(), nhist(), t2.data(), 6, d_adot.rawptr()); - std::vector t3v(sz); - double * t3 = &t3v[0]; - flow_->dh_ds_temp(s, alpha, T, t3); - for (int i=0; idh_ds_time(s, alpha, T, t3); - for (int i=0; i(); + flow_->dh_ds_temp(s.data(), alpha.rawptr(), T, t3.rawptr()); + d_adot += t3 * Tdot; + flow_->dh_ds_time(s.data(), alpha.rawptr(), T, t3.rawptr()); + return d_adot + t3 * kap; } -void WalkerKremplSwitchRule::da_da(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot) +History WalkerKremplSwitchRule::da_da(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { double dg; - flow_->y(s, alpha, T, dg); + flow_->y(s.data(), alpha.rawptr(), T, dg); - double kap; - kappa(edot, T, kap); + double kap = kappa(edot, T); int nh = nhist(); - int sz = nh * nh; - - flow_->dh_da(s, alpha, T, d_adot); - for (int i=0; i t1v(nh); - double * t1 = &t1v[0]; - flow_->h(s, alpha, T, t1); + History d_adot = gather_blank_history_().derivative(); + flow_->dh_da(s.data(), alpha.rawptr(), T, d_adot.rawptr()); + d_adot *= dg * kap; + + History t1 = gather_blank_history_(); + flow_->h(s.data(), alpha.rawptr(), T, t1.rawptr()); - std::vector t2v(nh); - double * t2 = &t2v[0]; - flow_->dy_da(s, alpha, T, t2); - - for (int i = 0 ; i < nh; i++) t2[i] *= kap; + History t2 = gather_blank_history_(); + flow_->dy_da(s.data(), alpha.rawptr(), T, t2.rawptr()); + t2 *= kap; - outer_update(t1, nh, t2, nh, d_adot); + outer_update(t1.rawptr(), nh, t2.rawptr(), nh, d_adot.rawptr()); - std::vector t3v(sz); - double * t3 = &t3v[0]; - flow_->dh_da_temp(s, alpha, T, t3); - for (int i=0; idh_da_time(s, alpha, T, t3); - for (int i=0; i(); + flow_->dh_da_temp(s.data(), alpha.rawptr(), T, t3.rawptr()); + d_adot += t3 * Tdot; + flow_->dh_da_time(s.data(), alpha.rawptr(), T, t3.rawptr()); + return d_adot + t3 * kap; } -void WalkerKremplSwitchRule::da_de(const double * const s, const double * const alpha, - const double * const edot, double T, - double Tdot, - double * const d_adot) +History WalkerKremplSwitchRule::da_de(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { double dg; - flow_->y(s, alpha, T, dg); - - double dkap[6]; - dkappa(edot, T, dkap); + flow_->y(s.data(), alpha.rawptr(), T, dg); - int nh = nhist(); - double * hr = new double [nh]; - flow_->h(s, alpha, T, hr); - for (int i = 0; i < nh; i++) hr[i] *= dg; + Symmetric dkap = dkappa(edot, T); - outer_vec(hr, nh, dkap, 6, d_adot); + History hr = gather_blank_history_(); + flow_->h(s.data(), alpha.rawptr(), T, hr.rawptr()); + hr *= dg; + + History d_adot = gather_blank_history_().derivative(); + d_adot.zero(); + outer_vec(hr.rawptr(), nhist(), dkap.data(), 6, d_adot.rawptr()); - flow_->h_time(s, alpha, T, hr); - outer_update(hr, nh, dkap, 6, d_adot); + flow_->h_time(s.data(), alpha.rawptr(), T, hr.rawptr()); + outer_update(hr.rawptr(), nhist(), dkap.data(), 6, d_adot.rawptr()); - delete [] hr; + return d_adot; } -void WalkerKremplSwitchRule::work_rate(const double * const s, - const double * const alpha, - const double * const edot, double T, - double Tdot, double & p_dot) +double WalkerKremplSwitchRule::work_rate(const Symmetric & s, const History & alpha, + const Symmetric & edot, double T, double Tdot) { - double erate[6]; - std::fill(erate, erate+6, 0.0); + Symmetric erate; - double kap; - kappa(edot, T, kap); + double kap = kappa(edot, T); - double temp[6]; + Symmetric dir; double yv; - flow_->g(s, alpha, T, temp); - flow_->y(s, alpha, T, yv); - - for (int i=0; i<6; i++) { - erate[i] += yv * kap * temp[i]; - } + flow_->g(s.data(), alpha.rawptr(), T, dir.s()); + flow_->y(s.data(), alpha.rawptr(), T, yv); - flow_->g_temp(s, alpha, T, temp); - for (int i=0; i<6; i++) { - erate[i] += Tdot * temp[i]; - } + erate += yv * kap * dir; - flow_->g_time(s, alpha, T, temp); - for (int i=0; i<6; i++) { - erate[i] += temp[i]; - } + flow_->g_temp(s.data(), alpha.rawptr(), T, dir.s()); + erate += Tdot * dir; - p_dot = dot_vec(s, erate, 6); -} - -void WalkerKremplSwitchRule::elastic_strains(const double * const s_np1, double T_np1, - double * const e_np1) const -{ - double S[36]; - elastic_->S(T_np1, S); - mat_vec(S, 6, s_np1, 6, e_np1); + flow_->g_time(s.data(), alpha.rawptr(), T, dir.s()); + erate += dir * kap; + + return s.contract(erate); } void WalkerKremplSwitchRule::set_elastic_model(std::shared_ptr emodel) @@ -329,34 +250,24 @@ void WalkerKremplSwitchRule::set_elastic_model(std::shared_ptrvalue(T) + lambda_->value(T) * de / eps0_; + double de = std::sqrt(2.0/3.0) * edot.dev().norm(); + return 1.0 - lambda_->value(T) + lambda_->value(T) * de / eps0_; } -void WalkerKremplSwitchRule::dkappa(const double * const edot, double T, - double * const dkap) +Symmetric WalkerKremplSwitchRule::dkappa(const Symmetric & edot, double T) { - std::copy(edot, edot+6, dkap); - dev_vec(dkap); + Symmetric edev = edot.dev(); + double nde = edev.norm(); - if (norm2_vec(dkap, 6) == 0.0) { - for (size_t i = 0; i < 6; i++) - dkap[i] = 0.0; - return; + if (nde == 0.0) { + return Symmetric(); } - double fact = lambda_->value(T) / eps0_ * std::sqrt(2.0/3.0) / norm2_vec(dkap, 6); + double fact = lambda_->value(T) / eps0_ * std::sqrt(2.0/3.0) / nde; - for (size_t i = 0; i < 6; i++) - dkap[i] *= fact; + return edev * fact; } void WalkerKremplSwitchRule::override_guess(double * const x) @@ -1529,20 +1440,6 @@ State WrappedViscoPlasticFlowRule::make_state_(const double * const s, const dou return State(Symmetric(s), gather_hist_(alpha), T); } -size_t WrappedViscoPlasticFlowRule::nhist() const -{ - return blank_hist_().size(); -} - -void WrappedViscoPlasticFlowRule::init_hist(double * const h) const -{ - // Pointless memory error - std::fill(h, h+nhist(), 0.0); - // Actual stuff - History hv = gather_hist_(h); - initialize_hist(hv); -} - // Rate rule void WrappedViscoPlasticFlowRule::y(const double* const s, const double* const alpha, double T, double & yv) const @@ -1707,7 +1604,7 @@ void WrappedViscoPlasticFlowRule::dh_da_temp(const State & state, History & res) TestFlowRule::TestFlowRule(ParameterSet & params) : WrappedViscoPlasticFlowRule(params), eps0_(params.get_parameter("eps0")), - D_(params.get_parameter("D")), + D_(params.get_parameter(prefix("D"))), n_(params.get_parameter("n")), s0_(params.get_parameter("s0")), K_(params.get_parameter("K")) @@ -1740,19 +1637,19 @@ ParameterSet TestFlowRule::parameters() void TestFlowRule::populate_hist(History & h) const { - h.add("alpha"); - h.add("iso"); + h.add(prefix("alpha")); + h.add(prefix("iso")); } -void TestFlowRule::initialize_hist(History & h) const +void TestFlowRule::init_hist(History & h) const { - h.get("alpha") = 0.0; - h.get("iso") = s0_; + h.get(prefix("alpha")) = 0.0; + h.get(prefix("iso")) = s0_; } void TestFlowRule::y(const State & state, double & res) const { - double h = (std::sqrt(3.0/2.0) * state.S.dev().norm() - state.h.get("iso")) + double h = (std::sqrt(3.0/2.0) * state.S.dev().norm() - state.h.get(prefix("iso"))) / D_; if (h > 0.0) { res = eps0_ * std::pow(h, n_); @@ -1764,7 +1661,7 @@ void TestFlowRule::y(const State & state, double & res) const void TestFlowRule::dy_ds(const State & state, Symmetric & res) const { - double h = (std::sqrt(3.0/2.0) * state.S.dev().norm() - state.h.get("iso")) + double h = (std::sqrt(3.0/2.0) * state.S.dev().norm() - state.h.get(prefix("iso"))) / D_; if (h > 0.0) { res = eps0_ * n_ * std::pow(h, n_-1.0) * std::sqrt(3.0/2.0) * state.S.dev() @@ -1777,11 +1674,11 @@ void TestFlowRule::dy_ds(const State & state, Symmetric & res) const void TestFlowRule::dy_da(const State & state, History & res) const { - double h = (std::sqrt(3.0/2.0) * state.S.dev().norm() - state.h.get("iso")) + double h = (std::sqrt(3.0/2.0) * state.S.dev().norm() - state.h.get(prefix("iso"))) / D_; res.zero(); if (h > 0.0) { - res.get("iso") = -eps0_ * n_ * std::pow(h, n_-1.0) / D_; + res.get(prefix("iso")) = -eps0_ * n_ * std::pow(h, n_-1.0) / D_; } } @@ -1809,8 +1706,8 @@ void TestFlowRule::dg_da(const State & state, History & res) const void TestFlowRule::h(const State & state, History & res) const { - res.get("alpha") = 1.0; - res.get("iso") = K_; + res.get(prefix("alpha")) = 1.0; + res.get(prefix("iso")) = K_; } void TestFlowRule::dh_ds(const State & state, History & res) const @@ -1831,13 +1728,13 @@ WalkerFlowRule::WalkerFlowRule(ParameterSet & params) : n_(params.get_object_parameter("n")), k_(params.get_object_parameter("k")), m_(params.get_object_parameter("m")), - R_(params.get_object_parameter("R")), - D_(params.get_object_parameter("D")), + R_(params.get_object_parameter(prefix("R"))), + D_(params.get_object_parameter(prefix("D"))), X_(params.get_object_parameter_vector("X")) { // The variable names to something canonical - R_->set_name("R"); - D_->set_name("D"); + R_->set_name(prefix("R")); + D_->set_name(prefix("D")); int i = 0; for (auto X : X_) { X->set_name("X" + std::to_string(i)); @@ -1883,21 +1780,21 @@ ParameterSet WalkerFlowRule::parameters() void WalkerFlowRule::populate_hist(History & h) const { - h.add("alpha"); - h.add(R_->name()); - h.add(D_->name()); + h.add(prefix("alpha")); + h.add(prefix(R_->name())); + h.add(prefix(D_->name())); for (auto X : X_) { - h.add(X->name()); + h.add(prefix(X->name())); } } -void WalkerFlowRule::initialize_hist(History & h) const +void WalkerFlowRule::init_hist(History & h) const { - h.get("alpha") = 0; - h.get(R_->name()) = R_->initial_value(); - h.get(D_->name()) = D_->initial_value(); + h.get(prefix("alpha")) = 0; + h.get(prefix(R_->name())) = R_->initial_value(); + h.get(prefix(D_->name())) = D_->initial_value(); for (auto X : X_) { - h.get(X->name()) = X->initial_value(); + h.get(prefix(X->name())) = X->initial_value(); } } @@ -1913,7 +1810,7 @@ void WalkerFlowRule::dy_ds(const State & state, Symmetric & res) const res = Symmetric::zero(); else res = prefactor_(state) * dflow_(state) * - std::sqrt(3.0/2.0)/(state.h.get("D") * d.norm()) * + std::sqrt(3.0/2.0)/(state.h.get(prefix("D")) * d.norm()) * SymSymR4::id_dev().dot(d); } @@ -1922,12 +1819,12 @@ void WalkerFlowRule::dy_da(const State & state, History & res) const // These are very annoying because it covers all the history variables... // alpha - res.get("alpha") = eps0_->value(state.T) * - softening_->dphi(state.h.get("alpha"), state.T) * + res.get(prefix("alpha")) = eps0_->value(state.T) * + softening_->dphi(state.h.get(prefix("alpha")), state.T) * scaling_->value(state.T) * flow_(state); // R - double D = state.h.get("D"); + double D = state.h.get(prefix("D")); double D0 = D_->D_0(state.T); double Dx = D_->D_xi(state.T); double m = m_->value(state.T); @@ -1935,27 +1832,27 @@ void WalkerFlowRule::dy_da(const State & state, History & res) const double Dr = 1.0e-8; if ((D - D0) > 0) Dr = (D-D0)/Dx; - res.get("R") = -prefactor_(state) * dflow_(state) * + res.get(prefix("R")) = -prefactor_(state) * dflow_(state) * std::pow(Dr, m) / D; // D Symmetric d = state.S.dev() - TX_(state); double k = k_->value(state.T); - double R = state.h.get("R"); + double R = state.h.get(prefix("R")); double p1 = -(k + R) * m * std::pow(Dr, m-1.0) / (Dx*D); double p2 = -(std::sqrt(3.0/2.0) * d.norm() - (k + R) * std::pow(Dr, m)) / (D*D); - res.get("D") = prefactor_(state) * dflow_(state) * + res.get(prefix("D")) = prefactor_(state) * dflow_(state) * (p1 + p2); // The backstresses for (auto X : X_) if (d.norm() == 0) { - res.get(X->name()) = Symmetric::zero(); + res.get(prefix(X->name())) = Symmetric::zero(); } else { - res.get(X->name()) = -prefactor_(state) * dflow_(state) * - std::sqrt(3.0/2.0)/(state.h.get("D") * d.norm()) * d; + res.get(prefix(X->name())) = -prefactor_(state) * dflow_(state) * + std::sqrt(3.0/2.0)/(state.h.get(prefix("D")) * d.norm()) * d; } } @@ -1976,30 +1873,30 @@ void WalkerFlowRule::dg_ds(const State & state, SymSymR4 & res) const void WalkerFlowRule::dg_da(const State & state, History & res) const { - res.get("alpha") = Symmetric::zero(); - res.get("R") = Symmetric::zero(); - res.get("D") = Symmetric::zero(); + res.get(prefix("alpha")) = Symmetric::zero(); + res.get(prefix("R")) = Symmetric::zero(); + res.get(prefix("D")) = Symmetric::zero(); SymSymR4 G = G_(state); for (auto X : X_) - res.get(X->name()) = -G; + res.get(prefix(X->name())) = -G; } void WalkerFlowRule::h(const State & state, History & res) const { // Scalar variables - res.get("alpha") = 1.0; + res.get(prefix("alpha")) = 1.0; auto ss = scalar_state_(state); - ss.h = state.h.get("R"); - res.get("R") = R_->ratep(ss); - ss.h = state.h.get("D"); - res.get("D") = D_->ratep(ss); + ss.h = state.h.get(prefix("R")); + res.get(prefix("R")) = R_->ratep(ss); + ss.h = state.h.get(prefix("D")); + res.get(prefix("D")) = D_->ratep(ss); // Backstresses auto Ss = symmetric_state_(state); for (auto X : X_) { - Ss.h.copy_data(state.h.get(X->name()).data()); - res.get(X->name()) = X->ratep(Ss); + Ss.h.copy_data(state.h.get(prefix(X->name())).data()); + res.get(prefix(X->name())) = X->ratep(Ss); } } @@ -2007,7 +1904,7 @@ void WalkerFlowRule::dh_ds(const State & state, History & res) const { // Again highly annoying, but at least there's a pattern here // Alpha - res.get("alpha") = Symmetric::zero(); + res.get(prefix("alpha")) = Symmetric::zero(); // Common junk Symmetric dy; @@ -2018,15 +1915,15 @@ void WalkerFlowRule::dh_ds(const State & state, History & res) const auto ss = scalar_state_(state); // R - ss.h = state.h.get("R"); - res.get("R") = + ss.h = state.h.get(prefix("R")); + res.get(prefix("R")) = R_->d_ratep_d_s(ss) + R_->d_ratep_d_adot(ss) * dy + dg.dot(R_->d_ratep_d_g(ss)).transpose(); // D - ss.h = state.h.get("D"); - res.get("D") = + ss.h = state.h.get(prefix("D")); + res.get(prefix("D")) = D_->d_ratep_d_s(ss) + D_->d_ratep_d_adot(ss) * dy + dg.dot(D_->d_ratep_d_g(ss)).transpose(); @@ -2034,8 +1931,8 @@ void WalkerFlowRule::dh_ds(const State & state, History & res) const // Backstresses auto Ss = symmetric_state_(state); for (auto X : X_) { - Ss.h.copy_data(state.h.get(X->name()).data()); - res.get(X->name()) = + Ss.h.copy_data(state.h.get(prefix(X->name())).data()); + res.get(prefix(X->name())) = X->d_ratep_d_s(Ss) + douter(X->d_ratep_d_adot(Ss), dy) + X->d_ratep_d_g(Ss).dot(dg); @@ -2063,81 +1960,81 @@ void WalkerFlowRule::dh_da(const State & state, History & res) const // (zero) // R - ss.h = state.h.get("R"); + ss.h = state.h.get(prefix("R")); // a - res.get("R_alpha") = + res.get(dprefix("R", "alpha")) = R_->d_ratep_d_a(ss) - + R_->d_ratep_d_adot(ss) * dy.get("alpha") - + R_->d_ratep_d_g(ss).contract(dg.get("alpha")); + + R_->d_ratep_d_adot(ss) * dy.get(prefix("alpha")) + + R_->d_ratep_d_g(ss).contract(dg.get(prefix("alpha"))); // R - res.get("R_R") = + res.get(dprefix("R","R")) = R_->d_ratep_d_h(ss) - + R_->d_ratep_d_adot(ss) * dy.get("R") - + R_->d_ratep_d_g(ss).contract(dg.get("R")); + + R_->d_ratep_d_adot(ss) * dy.get(prefix("R")) + + R_->d_ratep_d_g(ss).contract(dg.get(prefix("R"))); // D - res.get("R_D") = + res.get(dprefix("R", "D")) = R_->d_ratep_d_D(ss) - + R_->d_ratep_d_adot(ss) * dy.get("D") - + R_->d_ratep_d_g(ss).contract(dg.get("D")); + + R_->d_ratep_d_adot(ss) * dy.get(prefix("D")) + + R_->d_ratep_d_g(ss).contract(dg.get(prefix("D"))); // backstresses for (auto X: X_) { - res.get("R_" + X->name()) = - R_->d_ratep_d_adot(ss) * dy.get(X->name()) - + dg.get(X->name()).dot(R_->d_ratep_d_g(ss)).transpose(); + res.get(dprefix("R", X->name())) = + R_->d_ratep_d_adot(ss) * dy.get(prefix(X->name())) + + dg.get(prefix(X->name())).dot(R_->d_ratep_d_g(ss)).transpose(); } // D - ss.h = state.h.get("D"); + ss.h = state.h.get(prefix("D")); // a - res.get("D_alpha") = + res.get(dprefix("D","alpha")) = D_->d_ratep_d_a(ss) - + D_->d_ratep_d_adot(ss) * dy.get("alpha") - + D_->d_ratep_d_g(ss).contract(dg.get("alpha")); + + D_->d_ratep_d_adot(ss) * dy.get(prefix("alpha")) + + D_->d_ratep_d_g(ss).contract(dg.get(prefix("alpha"))); // R - res.get("D_R") = - D_->d_ratep_d_adot(ss) * dy.get("R") - + D_->d_ratep_d_g(ss).contract(dg.get("R")); + res.get(dprefix("D","R")) = + D_->d_ratep_d_adot(ss) * dy.get(prefix("R")) + + D_->d_ratep_d_g(ss).contract(dg.get(prefix("R"))); // D - res.get("D_D") = + res.get(dprefix("D","D")) = D_->d_ratep_d_h(ss) - + D_->d_ratep_d_adot(ss) * dy.get("D") - + D_->d_ratep_d_g(ss).contract(dg.get("D")); + + D_->d_ratep_d_adot(ss) * dy.get(prefix("D")) + + D_->d_ratep_d_g(ss).contract(dg.get(prefix("D"))); // backstresses for (auto X: X_) { - res.get("D_" + X->name()) = - D_->d_ratep_d_adot(ss) * dy.get(X->name()) + res.get(dprefix("D", X->name())) = + D_->d_ratep_d_adot(ss) * dy.get(prefix(X->name())) + dg.get(X->name()).dot(D_->d_ratep_d_g(ss)).transpose(); } // And the backstresses... auto Ss = symmetric_state_(state); for (auto X : X_) { - Ss.h.copy_data(state.h.get(X->name()).data()); + Ss.h.copy_data(state.h.get(prefix(X->name())).data()); // a - res.get(X->name() + "_alpha") = + res.get(dprefix(X->name(),"alpha")) = X->d_ratep_d_a(Ss) - + X->d_ratep_d_adot(Ss) * dy.get("alpha") - + X->d_ratep_d_g(Ss).dot(dg.get("alpha")); + + X->d_ratep_d_adot(Ss) * dy.get(prefix("alpha")) + + X->d_ratep_d_g(Ss).dot(dg.get(prefix("alpha"))); // R - res.get(X->name() + "_R") = - X->d_ratep_d_adot(Ss) * dy.get("R") - + X->d_ratep_d_g(Ss).dot(dg.get("R")); + res.get(dprefix(X->name(), "R")) = + X->d_ratep_d_adot(Ss) * dy.get(prefix("R")) + + X->d_ratep_d_g(Ss).dot(dg.get(prefix("R"))); // D - res.get(X->name() + "_D") = + res.get(dprefix(X->name(), "D")) = X->d_ratep_d_D(Ss) - + X->d_ratep_d_adot(Ss) * dy.get("D") - + X->d_ratep_d_g(Ss).dot(dg.get("D")); + + X->d_ratep_d_adot(Ss) * dy.get(prefix("D")) + + X->d_ratep_d_g(Ss).dot(dg.get(prefix("D"))); // backstresses for (auto Y : X_) { - if (Y->name() == X->name()) { - res.get(X->name() + "_" + Y->name()) = X->d_ratep_d_h(Ss); + if (prefix(Y->name()) == prefix(X->name())) { + res.get(dprefix(X->name(), Y->name())) = X->d_ratep_d_h(Ss); } - res.get(X->name() + "_" + Y->name()) += - douter(X->d_ratep_d_adot(Ss), dy.get(Y->name())) - + X->d_ratep_d_g(Ss).dot(dg.get(Y->name())); + res.get(dprefix(X->name() ,Y->name())) += + douter(X->d_ratep_d_adot(Ss), dy.get(prefix(Y->name()))) + + X->d_ratep_d_g(Ss).dot(dg.get(prefix(Y->name()))); } } } @@ -2145,18 +2042,18 @@ void WalkerFlowRule::dh_da(const State & state, History & res) const void WalkerFlowRule::h_time(const State & state, History & res) const { // Scalar variables - res.get("alpha") = 0.0; + res.get(prefix("alpha")) = 0.0; auto ss = scalar_state_(state); - ss.h = state.h.get("R"); - res.get("R") = R_->ratet(ss); - ss.h = state.h.get("D"); - res.get("D") = D_->ratet(ss); + ss.h = state.h.get(prefix("R")); + res.get(prefix("R")) = R_->ratet(ss); + ss.h = state.h.get(prefix("D")); + res.get(prefix("D")) = D_->ratet(ss); // Backstresses auto Ss = symmetric_state_(state); for (auto X : X_) { - Ss.h.copy_data(state.h.get(X->name()).data()); - res.get(X->name()) = X->ratet(Ss); + Ss.h.copy_data(state.h.get(prefix(X->name())).data()); + res.get(prefix(X->name())) = X->ratet(Ss); } } @@ -2164,7 +2061,7 @@ void WalkerFlowRule::dh_ds_time(const State & state, History & res) const { // Again highly annoying, but at least there's a pattern here // Alpha - res.get("alpha") = Symmetric::zero(); + res.get(prefix("alpha")) = Symmetric::zero(); // Common junk Symmetric dy; @@ -2175,15 +2072,15 @@ void WalkerFlowRule::dh_ds_time(const State & state, History & res) const auto ss = scalar_state_(state); // R - ss.h = state.h.get("R"); - res.get("R") = + ss.h = state.h.get(prefix("R")); + res.get(prefix("R")) = R_->d_ratet_d_s(ss) + R_->d_ratet_d_adot(ss) * dy + dg.dot(R_->d_ratet_d_g(ss)).transpose(); // D - ss.h = state.h.get("D"); - res.get("D") = + ss.h = state.h.get(prefix("D")); + res.get(prefix("D")) = D_->d_ratet_d_s(ss) + D_->d_ratet_d_adot(ss) * dy + dg.dot(D_->d_ratet_d_g(ss)).transpose(); @@ -2191,8 +2088,8 @@ void WalkerFlowRule::dh_ds_time(const State & state, History & res) const // Backstresses auto Ss = symmetric_state_(state); for (auto X : X_) { - Ss.h.copy_data(state.h.get(X->name()).data()); - res.get(X->name()) = + Ss.h.copy_data(state.h.get(prefix(X->name())).data()); + res.get(prefix(X->name())) = X->d_ratet_d_s(Ss) + douter(X->d_ratet_d_adot(Ss), dy) + X->d_ratet_d_g(Ss).dot(dg); @@ -2220,81 +2117,81 @@ void WalkerFlowRule::dh_da_time(const State & state, History & res) const // (zero) // R - ss.h = state.h.get("R"); + ss.h = state.h.get(prefix("R")); // a - res.get("R_alpha") = + res.get(dprefix("R","alpha")) = R_->d_ratet_d_a(ss) - + R_->d_ratet_d_adot(ss) * dy.get("alpha") - + R_->d_ratet_d_g(ss).contract(dg.get("alpha")); + + R_->d_ratet_d_adot(ss) * dy.get(prefix("alpha")) + + R_->d_ratet_d_g(ss).contract(dg.get(prefix("alpha"))); // R - res.get("R_R") = + res.get(dprefix("R","R")) = R_->d_ratet_d_h(ss) - + R_->d_ratet_d_adot(ss) * dy.get("R") - + R_->d_ratet_d_g(ss).contract(dg.get("R")); + + R_->d_ratet_d_adot(ss) * dy.get(prefix("R")) + + R_->d_ratet_d_g(ss).contract(dg.get(prefix("R"))); // D - res.get("R_D") = + res.get(dprefix("R", "D")) = R_->d_ratet_d_D(ss) - + R_->d_ratet_d_adot(ss) * dy.get("D") - + R_->d_ratet_d_g(ss).contract(dg.get("D")); + + R_->d_ratet_d_adot(ss) * dy.get(prefix("D")) + + R_->d_ratet_d_g(ss).contract(dg.get(prefix("D"))); // backstresses for (auto X: X_) { - res.get("R_" + X->name()) = - R_->d_ratet_d_adot(ss) * dy.get(X->name()) - + dg.get(X->name()).dot(R_->d_ratet_d_g(ss)).transpose(); + res.get(dprefix("R", X->name())) = + R_->d_ratet_d_adot(ss) * dy.get(prefix(X->name())) + + dg.get(prefix(X->name())).dot(R_->d_ratet_d_g(ss)).transpose(); } // D - ss.h = state.h.get("D"); + ss.h = state.h.get(prefix("D")); // a - res.get("D_alpha") = + res.get(dprefix("D","alpha")) = D_->d_ratet_d_a(ss) - + D_->d_ratet_d_adot(ss) * dy.get("alpha") - + D_->d_ratet_d_g(ss).contract(dg.get("alpha")); + + D_->d_ratet_d_adot(ss) * dy.get(prefix("alpha")) + + D_->d_ratet_d_g(ss).contract(dg.get(prefix("alpha"))); // R - res.get("D_R") = - D_->d_ratet_d_adot(ss) * dy.get("R") - + D_->d_ratet_d_g(ss).contract(dg.get("R")); + res.get(dprefix("D","R")) = + D_->d_ratet_d_adot(ss) * dy.get(prefix("R")) + + D_->d_ratet_d_g(ss).contract(dg.get(prefix("R"))); // D - res.get("D_D") = + res.get(dprefix("D","D")) = D_->d_ratet_d_h(ss) - + D_->d_ratet_d_adot(ss) * dy.get("D") - + D_->d_ratet_d_g(ss).contract(dg.get("D")); + + D_->d_ratet_d_adot(ss) * dy.get(prefix("D")) + + D_->d_ratet_d_g(ss).contract(dg.get(prefix("D"))); // backstresses for (auto X: X_) { - res.get("D_" + X->name()) = - D_->d_ratet_d_adot(ss) * dy.get(X->name()) - + dg.get(X->name()).dot(D_->d_ratet_d_g(ss)).transpose(); + res.get(dprefix("D",X->name())) = + D_->d_ratet_d_adot(ss) * dy.get(prefix(X->name())) + + dg.get(prefix(X->name())).dot(D_->d_ratet_d_g(ss)).transpose(); } // And the backstresses... auto Ss = symmetric_state_(state); for (auto X : X_) { - Ss.h.copy_data(state.h.get(X->name()).data()); + Ss.h.copy_data(state.h.get(prefix(X->name())).data()); // a - res.get(X->name() + "_alpha") = + res.get(dprefix(X->name(), "alpha")) = X->d_ratet_d_a(Ss) - + X->d_ratet_d_adot(Ss) * dy.get("alpha") - + X->d_ratet_d_g(Ss).dot(dg.get("alpha")); + + X->d_ratet_d_adot(Ss) * dy.get(prefix("alpha")) + + X->d_ratet_d_g(Ss).dot(dg.get(prefix("alpha"))); // R - res.get(X->name() + "_R") = - X->d_ratet_d_adot(Ss) * dy.get("R") - + X->d_ratet_d_g(Ss).dot(dg.get("R")); + res.get(dprefix(X->name(), "R")) = + X->d_ratet_d_adot(Ss) * dy.get(prefix("R")) + + X->d_ratet_d_g(Ss).dot(dg.get(prefix("R"))); // D - res.get(X->name() + "_D") = + res.get(dprefix(X->name(), "D")) = X->d_ratet_d_D(Ss) - + X->d_ratet_d_adot(Ss) * dy.get("D") - + X->d_ratet_d_g(Ss).dot(dg.get("D")); + + X->d_ratet_d_adot(Ss) * dy.get(prefix("D")) + + X->d_ratet_d_g(Ss).dot(dg.get(prefix("D"))); // backstresses for (auto Y : X_) { - if (Y->name() == X->name()) { - res.get(X->name() + "_" + Y->name()) = X->d_ratet_d_h(Ss); + if (prefix(Y->name()) == prefix(X->name())) { + res.get(dprefix(X->name(), Y->name())) = X->d_ratet_d_h(Ss); } - res.get(X->name() + "_" + Y->name()) += - douter(X->d_ratet_d_adot(Ss), dy.get(Y->name())) - + X->d_ratet_d_g(Ss).dot(dg.get(Y->name())); + res.get(dprefix(X->name(), Y->name())) += + douter(X->d_ratet_d_adot(Ss), dy.get(prefix(Y->name()))) + + X->d_ratet_d_g(Ss).dot(dg.get(prefix(Y->name()))); } } } @@ -2303,7 +2200,7 @@ Symmetric WalkerFlowRule::TX_(const State & state) const { Symmetric res = Symmetric::zero(); for (auto X : X_) - res += state.h.get(X->name()); + res += state.h.get(prefix(X->name())); return res; } @@ -2312,9 +2209,9 @@ ScalarInternalVariable::VariableState WalkerFlowRule::scalar_state_( { ScalarInternalVariable::VariableState vstate; - vstate.a = state.h.get("alpha"); + vstate.a = state.h.get(prefix("alpha")); y(state, vstate.adot); - vstate.D = state.h.get("D"); + vstate.D = state.h.get(prefix("D")); vstate.s = state.S; g(state, vstate.g); vstate.T = state.T; @@ -2327,9 +2224,9 @@ SymmetricInternalVariable::VariableState WalkerFlowRule::symmetric_state_( { SymmetricInternalVariable::VariableState vstate; - vstate.a = state.h.get("alpha"); + vstate.a = state.h.get(prefix("alpha")); y(state, vstate.adot); - vstate.D = state.h.get("D"); + vstate.D = state.h.get(prefix("D")); vstate.s = state.S; g(state, vstate.g); vstate.T = state.T; @@ -2340,7 +2237,7 @@ SymmetricInternalVariable::VariableState WalkerFlowRule::symmetric_state_( double WalkerFlowRule::prefactor_(const State & state) const { return eps0_->value(state.T) * - softening_->phi(state.h.get("alpha"), state.T) * + softening_->phi(state.h.get(prefix("alpha")), state.T) * scaling_->value(state.T); } @@ -2348,7 +2245,7 @@ double WalkerFlowRule::flow_(const State & state) const { Symmetric d = state.S.dev() - TX_(state); double Y = Y_(state); - double h = (std::sqrt(3.0/2.0) * d.norm() - Y) / state.h.get("D"); + double h = (std::sqrt(3.0/2.0) * d.norm() - Y) / state.h.get(prefix("D")); if (h <= 0.0) return 0.0; else @@ -2359,7 +2256,7 @@ double WalkerFlowRule::dflow_(const State & state) const { Symmetric d = state.S.dev() - TX_(state); double Y = Y_(state); - double h = (std::sqrt(3.0/2.0) * d.norm() - Y) / state.h.get("D"); + double h = (std::sqrt(3.0/2.0) * d.norm() - Y) / state.h.get(prefix("D")); if (h <= 0.0) return 0.0; else @@ -2368,9 +2265,9 @@ double WalkerFlowRule::dflow_(const State & state) const double WalkerFlowRule::Y_(const State & state) const { - double xi = (state.h.get("D") - D_->D_0(state.T)) / D_->D_xi(state.T); + double xi = (state.h.get(prefix("D")) - D_->D_0(state.T)) / D_->D_xi(state.T); if (xi < 0.0) xi = 0.0; - return (k_->value(state.T) + state.h.get("R")) * std::pow(xi, + return (k_->value(state.T) + state.h.get(prefix("R"))) * std::pow(xi, m_->value(state.T)); } diff --git a/src/walker_wrap.cxx b/src/walker_wrap.cxx index 6c447f16..256d8dc7 100644 --- a/src/walker_wrap.cxx +++ b/src/walker_wrap.cxx @@ -26,22 +26,9 @@ PYBIND11_MODULE(walker, m) { "flow", "lambda", "eps_ref"}); })) - .def("kappa", - [](WalkerKremplSwitchRule & m, py::array_t eps, double T) -> double - { - double res; - m.kappa(arr2ptr(eps), T, res); - return res; - }, "Rate sliding function") - .def("dkappa", - [](WalkerKremplSwitchRule & m, py::array_t eps, double T) -> py::array_t - { - auto f = alloc_vec(6); - m.dkappa(arr2ptr(eps), T, arr2ptr(f)); - return f; - }, "Derivative of the kappa function wrt strain rate.") + .def("kappa", &WalkerKremplSwitchRule::kappa, "Rate scaling function") + .def("dkappa", &WalkerKremplSwitchRule::dkappa, + "Derivative of the kappa function wrt strain rate.") ; py::class_>(m, @@ -276,21 +263,6 @@ PYBIND11_MODULE(walker, m) { py::class_>(m, "WrappedViscoPlasticFlowRule") - .def("populate_hist", - [](WrappedViscoPlasticFlowRule & m) -> History - { - History h; - m.populate_hist(h); - return h; - }, "Return a blank history") - .def("initialize_hist", - [](WrappedViscoPlasticFlowRule & m) -> History - { - History h; - m.populate_hist(h); - m.initialize_hist(h); - return h; - }, "Initialize the history, including setting the initial conditions.") .def("y_wrap", [](WrappedViscoPlasticFlowRule & m, State & state) -> double { diff --git a/test/nicediff.py b/test/nicediff.py index f344a99a..194437a5 100644 --- a/test/nicediff.py +++ b/test/nicediff.py @@ -27,10 +27,10 @@ def dfn(x): return differentiate_new(dfn, vec) -def diff_symmetric_symmetric(fn, s0): +def diff_symmetric_symmetric(fn, s0, eps = 1e-6): dfn = lambda s: fn(tensors.Symmetric(usym(s))).data - return tensors.SymSymR4(differentiate_new(dfn, s0.data)) + return tensors.SymSymR4(differentiate_new(dfn, s0.data, eps = eps)) def diff_symmetric_skew(fn, w0): dfn = lambda w: fn(tensors.Skew(uskew(w))).data diff --git a/test/test_creep.py b/test/test_creep.py index 96fb6db9..5d7f42b1 100644 --- a/test/test_creep.py +++ b/test/test_creep.py @@ -5,6 +5,7 @@ import unittest from common import * +from nicediff import * import numpy as np import numpy.linalg as la @@ -335,28 +336,28 @@ def test_jacobian(self): self.assertTrue(np.allclose(J, nJ, rtol = 1.0e-4)) def test_df_ds(self): - dfn = lambda x: self.model.f(x, self.e, self.t, self.T) - nderiv = differentiate(dfn, self.s) - cderiv = self.model.df_ds(self.s, self.e, self.t, self.T) - self.assertTrue(np.allclose(nderiv, cderiv, rtol = 1.0e-4)) + dfn = lambda x: self.model.f(x, self.E, self.t, self.T) + nderiv = diff_symmetric_symmetric(dfn, self.S) + cderiv = self.model.df_ds(self.S, self.E, self.t, self.T) + self.assertTrue(np.allclose(nderiv.data, cderiv.data, rtol = 1.0e-4)) def test_df_de(self): - dfn = lambda x: self.model.f(self.s, x, self.t, self.T) - nderiv = differentiate(dfn, self.e) - cderiv = self.model.df_de(self.s, self.e, self.t, self.T) - self.assertTrue(np.allclose(nderiv, cderiv, rtol = 1.0e-4)) + dfn = lambda x: self.model.f(self.S, x, self.t, self.T) + nderiv = diff_symmetric_symmetric(dfn, self.E) + cderiv = self.model.df_de(self.S, self.E, self.t, self.T) + self.assertTrue(np.allclose(nderiv.data, cderiv.data, rtol = 1.0e-4)) def test_df_dt(self): - dfn = lambda x: self.model.f(self.s, self.e, x, self.T) - nderiv = differentiate(dfn, self.t) - cderiv = self.model.df_dt(self.s, self.e, self.t, self.T) - self.assertTrue(np.allclose(nderiv, cderiv)) + dfn = lambda x: self.model.f(self.S, self.E, x, self.T) + nderiv = diff_symmetric_scalar(dfn, self.t) + cderiv = self.model.df_dt(self.S, self.E, self.t, self.T) + self.assertTrue(np.allclose(nderiv.data, cderiv.data)) def test_df_dT(self): - dfn = lambda x: self.model.f(self.s, self.e, self.t, x) - nderiv = differentiate(dfn, self.T) - cderiv = self.model.df_dT(self.s, self.e, self.t, self.T) - self.assertTrue(np.allclose(nderiv, cderiv)) + dfn = lambda x: self.model.f(self.S, self.E, self.t, x) + nderiv = diff_symmetric_scalar(dfn, self.T) + cderiv = self.model.df_dT(self.S, self.E, self.t, self.T) + self.assertTrue(np.allclose(nderiv.data, cderiv.data)) class TestJ2Creep(unittest.TestCase, CommonCreepModel): def setUp(self): @@ -369,7 +370,9 @@ def setUp(self): self.model = creep.J2CreepModel(self.smodel) self.s = np.array([100.0,-25.0,-5.0, 20.0,15.0,3.0]) + self.S = tensors.Symmetric(usym(self.s)) self.e = np.array([0.05, -0.01, -0.01, 0.025, 0.03, -0.01]) + self.E = tensors.Symmetric(usym(self.e)) self.x = np.array([0.06, 0.01, 0.02, 0.01, 0.02, -0.05]) self.T = 300.0 self.t = 10.0 @@ -381,19 +384,21 @@ def setUp(self): self.ee = np.sqrt(2.0/3.0) * la.norm(self.e) def test_f(self): - f_direct = self.model.f(self.s, self.e, self.t, self.T) + f_direct = self.model.f(self.S, self.E, self.t, self.T) g_direct = self.smodel.g(self.se, self.ee, self.t, self.T) f_calc = g_direct * 3.0 / 2.0 * self.sdev / self.se - self.assertTrue(np.allclose(f_direct, f_calc)) + self.assertTrue(np.allclose(f_direct.data, f_calc.data)) def test_f_uni(self): """ Make sure all our "effectives" work out correctly """ s = np.array([100.0, 0, 0, 0, 0, 0]) + S = tensors.Symmetric(usym(s)) e = np.array([0.1, -0.05, -0.05, 0, 0, 0]) - f_direct = self.model.f(s, e, self.t, self.T) + E = tensors.Symmetric(usym(e)) + f_direct = self.model.f(S, E, self.t, self.T) sdev = s - np.array([1,1,1,0,0,0]) * np.sum(s[:3]) / 3.0 se = np.sqrt(3.0/2.0) * la.norm(sdev) @@ -401,11 +406,11 @@ def test_f_uni(self): g_direct = self.smodel.g(se, ee, self.t, self.T) - self.assertTrue(np.isclose(g_direct, f_direct[0])) + self.assertTrue(np.isclose(g_direct, f_direct.data[0])) - self.assertTrue(np.isclose(-g_direct/2.0, f_direct[1])) - self.assertTrue(np.isclose(-g_direct/2.0, f_direct[2])) + self.assertTrue(np.isclose(-g_direct/2.0, f_direct.data[1])) + self.assertTrue(np.isclose(-g_direct/2.0, f_direct.data[2])) - self.assertTrue(np.allclose([0,0,0], f_direct[3:])) + self.assertTrue(np.allclose([0,0,0], f_direct.data[3:])) diff --git a/test/test_crystaldamage.py b/test/test_crystaldamage.py index db861c92..abf3d800 100644 --- a/test/test_crystaldamage.py +++ b/test/test_crystaldamage.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -from neml import history, interpolate +from neml import interpolate from neml.math import tensors, rotations, matrix, projections from neml.cp import crystallography, sliprules, crystaldamage, slipharden @@ -94,8 +94,8 @@ def setUp(self): self.nfunc, self.L) self.huse = history.History() - self.hmodel.populate_history(self.huse) - self.model.populate_history(self.huse) + self.hmodel.populate_hist(self.huse) + self.model.populate_hist(self.huse) for i in range(12): self.huse.set_scalar("strength"+str(i), 2.0) @@ -162,8 +162,8 @@ def setUp(self): self.model = crystaldamage.NilDamageModel() self.huse = history.History() - self.hmodel.populate_history(self.huse) - self.model.populate_history(self.huse) + self.hmodel.populate_hist(self.huse) + self.model.populate_hist(self.huse) for i in range(12): self.huse.set_scalar("strength"+str(i), 25.0) @@ -177,10 +177,10 @@ def setUp(self): def test_hist(self): test = history.History() - self.model.populate_history(test) + self.model.populate_hist(test) self.assertEqual(test.size, 1) self.assertEqual(test.items, ["whatever"]) - self.model.init_history(test) + self.model.init_hist(test) self.assertAlmostEqual(test.get_scalar("whatever"), 0.0) def test_projection(self): diff --git a/test/test_damage.py b/test/test_damage.py index 17e06717..491dc4ae 100644 --- a/test/test_damage.py +++ b/test/test_damage.py @@ -1,7 +1,7 @@ import sys sys.path.append('..') -from neml import interpolate, solvers, models, elasticity, ri_flow, hardening, surfaces, visco_flow, general_flow, creep, damage, larsonmiller +from neml import interpolate, solvers, models, elasticity, ri_flow, hardening, surfaces, visco_flow, general_flow, creep, damage, larsonmiller, history from common import * import unittest @@ -76,7 +76,10 @@ def test_ndamage(self): self.assertEqual(self.model.ndamage, 1) def test_init_damage(self): - self.assertTrue(np.allclose(self.model.init_damage(), np.zeros((1,)))) + h = history.History() + self.model.populate_damage(h) + self.model.init_damage(h) + self.assertTrue(np.allclose(h, np.zeros((1,)))) def test_ddamage_ddamage(self): dd_model = self.dmodel.ddamage_dd(self.d_np1, self.d_n, self.e_np1, self.e_n, @@ -158,13 +161,6 @@ def test_jacobian(self): class CommonDamagedModel(object): def test_nstore(self): self.assertEqual(self.model.nstore, self.bmodel.nstore + self.model.ndamage) - - def test_store(self): - base = self.bmodel.init_store() - damg = self.model.init_damage() - comp = list(damg) + list(base) - fromm = self.model.init_store() - self.assertTrue(np.allclose(fromm, comp)) def test_tangent_proportional_strain(self): t_n = 0.0 diff --git a/test/test_elastic_switch.py b/test/test_elastic_switch.py index 1acd48d1..99fdc374 100644 --- a/test/test_elastic_switch.py +++ b/test/test_elastic_switch.py @@ -39,7 +39,7 @@ def test_perfect_plasicity(self): self.are_equal(self.elastic2, model.elastic) def test_ri_plasticity(self): - surface = surfaces.IsoJ2() + surface = surfaces.IsoKinJ2() sy = 100.0 K = 1000.0 H = 500.0 diff --git a/test/test_general_flow.py b/test/test_general_flow.py index 2878894d..fe179836 100644 --- a/test/test_general_flow.py +++ b/test/test_general_flow.py @@ -1,8 +1,10 @@ import sys sys.path.append('..') -from neml import general_flow, visco_flow, elasticity, surfaces, hardening +from neml import general_flow, visco_flow, elasticity, surfaces, hardening, history +from neml.math import tensors from common import * +from nicediff import * import unittest import numpy as np @@ -19,10 +21,10 @@ def test_ds_ds(self): h_np1 = self.gen_hist() dfn = lambda x: self.model.s(x, h_np1, e_dot, T_np1, T_dot) - num = differentiate(dfn, s_np1) + num = diff_symmetric_symmetric(dfn, s_np1) should = self.model.ds_ds(s_np1, h_np1, e_dot, T_np1, T_dot) - self.assertTrue(np.allclose(num, should)) + self.assertTrue(np.allclose(num.data, should.data)) def test_ds_da(self): t_np1 = self.gen_t() @@ -34,10 +36,10 @@ def test_ds_da(self): h_np1 = self.gen_hist() dfn = lambda x: self.model.s(s_np1, x, e_dot, T_np1, T_dot) - num = differentiate(dfn, h_np1) + num = diff_symmetric_history(dfn, h_np1) should = self.model.ds_da(s_np1, h_np1, e_dot, T_np1, T_dot) - self.assertTrue(np.allclose(num, should, rtol = 1.0e-3)) + self.assertTrue(np.allclose(num, np.array(should).reshape(num.shape), rtol = 1.0e-3)) def test_ds_de(self): t_np1 = self.gen_t() @@ -49,10 +51,10 @@ def test_ds_de(self): h_np1 = self.gen_hist() dfn = lambda x: self.model.s(s_np1, h_np1, x, T_np1, T_dot) - num = differentiate(dfn, e_dot, eps = self.eps) + num = diff_symmetric_symmetric(dfn, e_dot, eps = self.eps) should = self.model.ds_de(s_np1, h_np1, e_dot, T_np1, T_dot) - self.assertTrue(np.allclose(num, should, rtol = 1.0e-3)) + self.assertTrue(np.allclose(num.data, should.data, rtol = 1.0e-2)) def test_da_ds(self): t_np1 = self.gen_t() @@ -64,10 +66,10 @@ def test_da_ds(self): h_np1 = self.gen_hist() dfn = lambda x: self.model.a(x, h_np1, e_dot, T_np1, T_dot) - num = differentiate(dfn, s_np1) + num = diff_history_symmetric(dfn, s_np1) should = self.model.da_ds(s_np1, h_np1, e_dot, T_np1, T_dot) - self.assertTrue(np.allclose(num, should, rtol = 1.0e-3)) + self.assertTrue(np.allclose(num, np.array(should).reshape(num.shape), rtol = 1.0e-3)) def test_da_da(self): t_np1 = self.gen_t() @@ -79,10 +81,10 @@ def test_da_da(self): h_np1 = self.gen_hist() dfn = lambda x: self.model.a(s_np1, x, e_dot, T_np1, T_dot) - num = differentiate(dfn, h_np1) + num = diff_history_history(dfn, h_np1) should = self.model.da_da(s_np1, h_np1, e_dot, T_np1, T_dot) - - self.assertTrue(np.allclose(num, should, rtol = 1.0e-3)) + + self.assertTrue(np.allclose(num, np.array(should).reshape(num.shape), rtol = 1.0e-3)) def test_da_de(self): t_np1 = self.gen_t() @@ -94,16 +96,16 @@ def test_da_de(self): h_np1 = self.gen_hist() dfn = lambda x: self.model.a(s_np1, h_np1, x, T_np1, T_dot) - num = differentiate(dfn, e_dot, eps = self.eps) + num = diff_history_symmetric(dfn, e_dot) should = self.model.da_de(s_np1, h_np1, e_dot, T_np1, T_dot) - self.assertTrue(np.allclose(num, should, rtol = 1.0e-3)) + self.assertTrue(np.allclose(num, np.array(should).reshape(num.shape), rtol = 1.0e-3)) class CommonTVPFlow(object): def test_history(self): - self.assertEqual(len(self.h_n), self.model.nhist) - self.assertTrue(np.allclose(self.h_n, self.model.init_hist())) + self.assertEqual(self.h_n.size, self.model.nhist) + self.assertTrue(np.allclose(self.h_n, self.model.initial_history())) def test_srate(self): t_np1 = self.gen_t() @@ -115,14 +117,14 @@ def test_srate(self): h_np1 = self.gen_hist() should = np.dot(self.emodel.C(T_np1), - e_dot - self.vmodel.g(s_np1, h_np1, T_np1) * - self.vmodel.y(s_np1, h_np1, T_np1) - - self.vmodel.g_temp(s_np1, h_np1, T_np1) * T_dot - - self.vmodel.g_time(s_np1, h_np1, T_np1)) + e_dot.data - self.vmodel.g(s_np1.data, h_np1, T_np1) * + self.vmodel.y(s_np1.data, h_np1, T_np1) - + self.vmodel.g_temp(s_np1.data, h_np1, T_np1) * T_dot - + self.vmodel.g_time(s_np1.data, h_np1, T_np1)) actual = self.model.s(s_np1, h_np1, e_dot, T_np1, T_dot) - self.assertTrue(np.allclose(should, actual)) + self.assertTrue(np.allclose(should, actual.data)) def test_hrate(self): t_np1 = self.gen_t() @@ -133,17 +135,17 @@ def test_hrate(self): s_np1 = self.gen_stress() h_np1 = self.gen_hist() - should = (self.vmodel.h(s_np1, h_np1, T_np1) * - self.vmodel.y(s_np1, h_np1, T_np1) + - self.vmodel.h_temp(s_np1, h_np1, T_np1) * T_dot + - self.vmodel.h_time(s_np1, h_np1, T_np1)) + should = (self.vmodel.h(s_np1.data, np.array(h_np1), T_np1) * + self.vmodel.y(s_np1.data, np.array(h_np1), T_np1) + + self.vmodel.h_temp(s_np1.data, np.array(h_np1), T_np1) * T_dot + + self.vmodel.h_time(s_np1.data, np.array(h_np1), T_np1)) actual = self.model.a(s_np1, h_np1, e_dot, T_np1, T_dot) self.assertTrue(np.allclose(should, actual)) -class TestTVPCheboche(unittest.TestCase, CommonGeneralFlow, CommonTVPFlow): +class TestTVPChaboche(unittest.TestCase, CommonGeneralFlow, CommonTVPFlow): def setUp(self): n = 20.0 eta = 108.0 @@ -188,11 +190,13 @@ def setUp(self): self.model = general_flow.TVPFlowRule(self.emodel, self.vmodel) self.T_n = 300.0 - self.e_n = np.zeros((6,)) + self.e_n = tensors.Symmetric(usym(np.zeros((6,)))) self.t_n = 0.0 - self.h_n = np.zeros((1+6*self.m,)) + self.h_n = history.History() + self.model.populate_hist(self.h_n) + self.h_n.copy_data(np.zeros((1+6*self.m,))) - self.eps = 1.0e-3 + self.eps = 1.0e-2 def gen_hist(self): h = np.array([0.1,50,-30,40,60,-80,-30,-100,-15,-30,-50,100,50,60,-60,50, @@ -200,13 +204,17 @@ def gen_hist(self): for i in range(self.m): h[1+i*6:1+(i+1)*6] = make_dev(h[1+i*6:1+(i+1)*6]) - return h + H = history.History() + self.model.populate_hist(H) + H.copy_data(h) + + return H def gen_stress(self): - return np.array([200.0,-200.0,100.0,50.0,25.0,-50.0]) + return tensors.Symmetric(usym(np.array([200.0,-200.0,100.0,50.0,25.0,-50.0]))) def gen_e(self): - return np.array([0.025,-0.01,-0.02,0.01,0.02,-0.03]) + return tensors.Symmetric(usym(np.array([0.025,-0.01,-0.02,0.01,0.02,-0.03]))) def gen_T(self): return 350 @@ -240,9 +248,11 @@ def setUp(self): self.model = general_flow.TVPFlowRule(self.emodel, self.vmodel) self.T_n = 300.0 - self.e_n = np.zeros((6,)) + self.e_n = tensors.Symmetric(usym(np.zeros((6,)))) self.t_n = 0.0 - self.h_n = np.zeros((2+12,)) + self.h_n = history.History() + self.model.populate_hist(self.h_n) + self.h_n.copy_data(np.zeros((2+12,))) self.eps = 1.0e-3 @@ -251,13 +261,17 @@ def gen_hist(self): for i in range(2): h[1+i*6:1+(i+1)*6] = make_dev(h[1+i*6:1+(i+1)*6]) - return h + H = history.History() + self.model.populate_hist(H) + H.copy_data(h) + + return H def gen_stress(self): - return np.array([200.0,-200.0,100.0,50.0,25.0,-50.0]) + return tensors.Symmetric(usym(np.array([200.0,-200.0,100.0,50.0,25.0,-50.0]))) def gen_e(self): - return np.array([0.025,-0.01,-0.02,0.01,0.02,-0.03]) + return tensors.Symmetric(usym(np.array([0.025,-0.01,-0.02,0.01,0.02,-0.03]))) def gen_T(self): return 350 diff --git a/test/test_hardening.py b/test/test_hardening.py index 50cba742..8de3c8a5 100644 --- a/test/test_hardening.py +++ b/test/test_hardening.py @@ -15,7 +15,7 @@ class CommonHardening(object): """ def test_history(self): self.assertEqual(self.model.nhist, len(self.hist0)) - self.assertTrue(np.allclose(self.model.init_hist(), self.hist0)) + self.assertTrue(np.allclose(self.model.initial_history(), self.hist0)) def test_gradient(self): dfn = lambda x: self.model.q(x, self.T) @@ -175,7 +175,7 @@ class CommonNonAssociative(object): def test_history(self): self.assertEqual(self.model.nhist, len(self.hist0)) self.assertEqual(self.model.ninter, self.conform) - self.assertTrue(np.allclose(self.model.init_hist(), self.hist0)) + self.assertTrue(np.allclose(self.model.initial_history(), self.hist0)) def gen_stress(self): s = np.array([-150,200,-50,80,-20,30]) diff --git a/test/test_hucocks.py b/test/test_hucocks.py index 6145a9e3..e9fccdad 100644 --- a/test/test_hucocks.py +++ b/test/test_hucocks.py @@ -593,8 +593,8 @@ def test_history(self): Paranoid check on the history state, given this is a kinda complicated model """ H1 = history.History() - self.model.populate_history(H1) - self.model.init_history(H1) + self.model.populate_hist(H1) + self.model.init_hist(H1) self.assertEqual(len(np.array(H1)), 12+3+3) diff --git a/test/test_kinematics.py b/test/test_kinematics.py index 996246e0..1c9fa78e 100644 --- a/test/test_kinematics.py +++ b/test/test_kinematics.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -from neml import history, interpolate, elasticity +from neml import interpolate, elasticity from neml.math import tensors, rotations from neml.cp import crystallography, slipharden, sliprules, inelasticity, kinematics, crystaldamage @@ -204,12 +204,12 @@ def setUp(self): def test_setup_history(self): H1 = history.History() - self.model.populate_history(H1) - self.model.init_history(H1) + self.model.populate_hist(H1) + self.model.init_hist(H1) H2 = history.History() - self.imodel.populate_history(H2) - self.imodel.init_history(H2) + self.imodel.populate_hist(H2) + self.imodel.init_hist(H2) self.assertTrue(np.allclose(np.array(H1), np.array(H2))) diff --git a/test/test_ri_flow.py b/test/test_ri_flow.py index c0bad9fa..aff7a5d7 100644 --- a/test/test_ri_flow.py +++ b/test/test_ri_flow.py @@ -18,7 +18,7 @@ def gen_stress(self): def test_history(self): self.assertEqual(self.model.nhist, len(self.hist0)) - self.assertTrue(np.allclose(self.model.init_hist(), self.hist0)) + self.assertTrue(np.allclose(self.model.initial_history(), self.hist0)) def test_df_ds(self): stress = self.gen_stress() diff --git a/test/test_slipharden.py b/test/test_slipharden.py index 59db8005..fbe8f91d 100644 --- a/test/test_slipharden.py +++ b/test/test_slipharden.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -from neml import history, interpolate +from neml import interpolate from neml.math import tensors, rotations, matrix from neml.cp import crystallography, slipharden, sliprules @@ -581,8 +581,8 @@ def setUp(self): def test_initialize_hist(self): H = history.History() - self.model.populate_history(H) - self.model.init_history(H) + self.model.populate_hist(H) + self.model.init_hist(H) self.assertTrue(np.isclose(H.get_scalar('strength'), 0.0)) def test_static_strength(self): @@ -644,8 +644,8 @@ def setUp(self): def test_initialize_hist(self): H = history.History() - self.model.populate_history(H) - self.model.init_history(H) + self.model.populate_hist(H) + self.model.init_hist(H) self.assertTrue(np.isclose(H.get_scalar('strength'), 0.0)) def test_static_strength(self): @@ -701,8 +701,8 @@ def test_get_vnames(self): def test_initialize_hist(self): H = history.History() - self.model.populate_history(H) - self.model.init_history(H) + self.model.populate_hist(H) + self.model.init_hist(H) self.assertTrue(np.isclose(H.get_scalar(self.vname), 0.0)) def test_static_strength(self): @@ -770,8 +770,8 @@ def setUp(self): def test_initialize_hist(self): H = history.History() - self.model.populate_history(H) - self.model.init_history(H) + self.model.populate_hist(H) + self.model.init_hist(H) self.assertTrue(np.isclose(H.get_scalar('strength0'), 0.0)) self.assertTrue(np.isclose(H.get_scalar('strength1'), 0.0)) @@ -831,8 +831,8 @@ def setUp(self): def test_initialize_hist(self): H = history.History() - self.model.populate_history(H) - self.model.init_history(H) + self.model.populate_hist(H) + self.model.init_hist(H) self.assertTrue(np.isclose(H.get_scalar('strength'), 0.0)) def test_static_strength(self): diff --git a/test/test_sliprules.py b/test/test_sliprules.py index 98bdfd6a..6aceded7 100644 --- a/test/test_sliprules.py +++ b/test/test_sliprules.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -from neml import history, interpolate +from neml import interpolate from neml.math import tensors, rotations, matrix from neml.cp import crystallography, slipharden, sliprules @@ -43,14 +43,14 @@ def test_d_hist_rate_d_hist(self): class CommonSlipMultiStrengthSlipRule(object): def test_setup_history(self): model_hist = history.History() - self.model.populate_history(model_hist) - self.model.init_history(model_hist) + self.model.populate_hist(model_hist) + self.model.init_hist(model_hist) manual_hist = history.History() for strength in self.strengths: Hs = history.History() - strength.populate_history(Hs) - strength.init_history(Hs) + strength.populate_hist(Hs) + strength.init_hist(Hs) manual_hist.add_union(Hs) self.assertTrue(np.allclose(np.array(model_hist), @@ -194,8 +194,8 @@ def setUp(self): self.model = sliprules.KinematicPowerLawSlipRule(self.backstrength, self.isostrength, self.flowresistance, self.g0, self.n) - self.model.populate_history(self.H) - self.model.init_history(self.H) + self.model.populate_hist(self.H) + self.model.init_hist(self.H) self.strength_values = np.linspace(0,10,36) + 5.0 self.H.copy_data(self.strength_values) @@ -205,12 +205,12 @@ def setUp(self): class CommonSlipStrengthSlipRule(CommonSlipMultiStrengthSlipRule): def test_init_hist(self): H1 = history.History() - self.model.populate_history(H1) - self.model.init_history(H1) + self.model.populate_hist(H1) + self.model.init_hist(H1) H2 = history.History() - self.strengthmodel.populate_history(H2) - self.strengthmodel.init_history(H2) + self.strengthmodel.populate_hist(H2) + self.strengthmodel.init_hist(H2) self.assertTrue(np.allclose(np.array(H1), np.array(H2))) diff --git a/test/test_visco_flow.py b/test/test_visco_flow.py index e6cb3416..005cc663 100644 --- a/test/test_visco_flow.py +++ b/test/test_visco_flow.py @@ -54,7 +54,7 @@ def gen_stress(self): def test_history(self): self.assertEqual(self.model.nhist, len(self.hist0)) - self.assertTrue(np.allclose(self.model.init_hist(), self.hist0)) + self.assertTrue(np.allclose(self.model.initial_history(), self.hist0)) def test_dy_ds(self): stress = self.gen_stress() diff --git a/test/test_walker.py b/test/test_walker.py index 3c30c2a2..c4aaf2ea 100644 --- a/test/test_walker.py +++ b/test/test_walker.py @@ -35,35 +35,39 @@ def setUp(self): self.lv, self.eps0) self.T_n = 300.0 - self.e_n = np.zeros((6,)) + self.e_n = tensors.Symmetric(usym(np.zeros((6,)))) self.t_n = 0.0 - self.h_n = np.zeros((2,)) + self.h_n = history.History() + self.model.populate_hist(self.h_n) + self.h_n.copy_data(np.zeros((2,))) self.eps = 1.0e-6 def test_kappa(self): exact = self.model.kappa(self.gen_edot(self.gen_e(), self.gen_t()), self.gen_T()) - edev = make_dev(self.gen_edot(self.gen_e(), self.gen_t())) + edev = make_dev(self.gen_edot(self.gen_e(), self.gen_t()).data) en = la.norm(edev) should = 1.0 - self.lv + self.lv * np.sqrt(2.0/3.0) * en / self.eps0 self.assertAlmostEqual(should, exact) def test_dkappa(self): exact = self.model.dkappa(self.gen_edot(self.gen_e(), self.gen_t()), self.gen_T()) - should = differentiate(lambda e: self.model.kappa(e, self.gen_T()), + should = diff_scalar_symmetric(lambda e: self.model.kappa(e, self.gen_T()), self.gen_edot(self.gen_e(), self.gen_t())) - self.assertTrue(np.allclose(exact.flatten(),should.flatten(), rtol = 1e-4)) + self.assertTrue(np.allclose(exact.data,should.data, rtol = 1e-4)) def gen_hist(self): - h = np.array([0.1,175.0]) - return h + H = history.History() + self.model.populate_hist(H) + H.copy_data(np.array([0.1,175.0])) + return H def gen_stress(self): - return np.array([200.0,-200.0,100.0,50.0,25.0,-50.0]) + return tensors.Symmetric(usym(np.array([200.0,-200.0,100.0,50.0,25.0,-50.0]))) def gen_e(self): - return np.array([0.025,-0.01,-0.02,0.01,0.02,-0.03]) + return tensors.Symmetric(usym(np.array([0.025,-0.01,-0.02,0.01,0.02,-0.03]))) def gen_T(self): return 350 @@ -938,7 +942,8 @@ def setUp(self): [300.0,50.0,25.0], [50.0,150.0,-20.0], [25.0,-20.0,-100.0]]) - self.h = self.model.populate_hist() + self.h = history.History() + self.model.populate_hist(self.h) self.h.set_scalar("alpha", 0.1) self.h.set_scalar("iso", 200.0) self.T = 300.0 @@ -957,12 +962,12 @@ def test_nhist(self): self.assertEqual(self.model.nhist, 2) def test_setup_hist(self): - hobj = self.model.populate_hist() + hobj = self.model.initial_history() self.assertEqual(hobj.size, 2) self.assertTrue(hobj.items, ["alpha", "iso"]) def test_initialize_hist(self): - h = self.model.initialize_hist() + h = self.model.initial_history() self.assertAlmostEqual(h.get_scalar("alpha"), 0.0) self.assertAlmostEqual(h.get_scalar("iso"), self.s0) @@ -979,7 +984,8 @@ def test_g(self): self.assertEqual(should, actual) def test_h(self): - should = self.model.populate_hist() + should = history.History() + self.model.populate_hist(should) should.set_scalar("alpha", 1.0) should.set_scalar("iso", self.K) @@ -1110,8 +1116,9 @@ def setUp(self): [12.0, 18.0,50.0]]).dev() self.X = self.X1 + self.X2 - - self.h = self.model.populate_hist() + + self.h = history.History() + self.model.populate_hist(self.h) self.h.set_scalar("alpha", self.a) self.h.set_scalar("R", self.R) self.h.set_scalar("D", self.D) @@ -1141,12 +1148,13 @@ def test_nhist(self): self.assertEqual(self.model.nhist, self.nhist) def test_setup_hist(self): - hobj = self.model.populate_hist() + hobj = history.History() + self.model.populate_hist(hobj) self.assertEqual(hobj.size, self.nhist) self.assertTrue(hobj.items, ["alpha", "R", "D", "X0", "X1"]) def test_initialize_hist(self): - h = self.model.initialize_hist() + h = self.model.initial_history() self.assertAlmostEqual(h.get_scalar("alpha"), 0.0) self.assertAlmostEqual(h.get_scalar("R"), 0.0) self.assertAlmostEqual(h.get_scalar("D"), self.D_0) @@ -1179,7 +1187,8 @@ def test_g(self): def test_h(self): mval = self.model.h_wrap(self.state) - sval = self.model.populate_hist() + sval = history.History() + self.model.populate_hist(sval) # All this for alpha... xi = (self.D - self.D_0) / self.D_xi @@ -1220,7 +1229,8 @@ def test_h(self): def test_h_time(self): mval = self.model.h_time_wrap(self.state) - sval = self.model.populate_hist() + sval = history.History() + self.model.populate_hist(sval) # All this for alpha... xi = (self.D - self.D_0) / self.D_xi diff --git a/util/abaqus/report.cxx b/util/abaqus/report.cxx index c9606f35..fb4fd327 100644 --- a/util/abaqus/report.cxx +++ b/util/abaqus/report.cxx @@ -17,7 +17,7 @@ int main(int argc, char ** argv) { double * ihist = new double[n]; - model->init_hist(ihist); + model->init_store(ihist); std::cout << std::endl; diff --git a/util/cxx_interface/cxxsimple.cxx b/util/cxx_interface/cxxsimple.cxx index 6b233426..ff21b10f 100644 --- a/util/cxx_interface/cxxsimple.cxx +++ b/util/cxx_interface/cxxsimple.cxx @@ -27,7 +27,7 @@ int main(int argc, char** argv) double * h_n = new double [model->nstore()]; double * h_np1 = new double [model->nstore()]; - model->init_hist(h_n); + model->init_store(h_n); double e_n[6], e_np1[6], s_n[6], s_np1[6], A_np1[36]; std::fill(e_n, e_n+6, 0.0); diff --git a/util/string_interface/cxxstring.cxx b/util/string_interface/cxxstring.cxx index 21a45f37..d39efd7e 100644 --- a/util/string_interface/cxxstring.cxx +++ b/util/string_interface/cxxstring.cxx @@ -24,7 +24,7 @@ int main(int argc, char** argv) double * h_n = new double [model->nstore()]; double * h_np1 = new double [model->nstore()]; - model->init_hist(h_n); + model->init_store(h_n); double e_n[6], e_np1[6], s_n[6], s_np1[6], A_np1[36]; std::fill(e_n, e_n+6, 0.0);