#include "ExtrinsicModelDriftDiffusion.h"
#include "ATC_Error.h"
#include "FieldEulerIntegrator.h"
#include "ATC_Coupling.h"
#include "LammpsInterface.h"
#include "PrescribedDataManager.h"
#include "PhysicsModel.h"
#include "LinearSolver.h"
#include "PoissonSolver.h"
#include "SchrodingerSolver.h"
#include "Utility.h"
#include <utility>
using ATC_Utility::to_string;
using std::cout;
using std::string;
using std::set;
using std::pair;
using std::vector;
namespace ATC {
ExtrinsicModelDriftDiffusion::ExtrinsicModelDriftDiffusion
(ExtrinsicModelManager * modelManager,
ExtrinsicModelType modelType,
string matFileName) :
ExtrinsicModelTwoTemperature(modelManager,modelType,matFileName),
continuityIntegrator_(NULL),
poissonSolverType_(DIRECT), poissonSolver_(NULL),
baseSize_(0),
electronDensityEqn_(ELECTRON_CONTINUITY),
fluxUpdateFreq_(1),
schrodingerSolverType_(DIRECT), schrodingerSolver_(NULL),
schrodingerPoissonMgr_(),
schrodingerPoissonSolver_(NULL),
maxConsistencyIter_(0), maxConstraintIter_(1),
safe_dEf_(0.1), Ef_shift_(0.0),
oneD_(false), oneDcoor_(0), oneDconserve_(0)
{
if (physicsModel_) delete physicsModel_;
if (modelType == DRIFT_DIFFUSION_EQUILIBRIUM) {
physicsModel_ = new PhysicsModelDriftDiffusionEquilibrium(matFileName);
electronDensityEqn_ = ELECTRON_EQUILIBRIUM;
}
else if (modelType == DRIFT_DIFFUSION_SCHRODINGER) {
physicsModel_ = new PhysicsModelDriftDiffusionSchrodinger(matFileName);
electronDensityEqn_ = ELECTRON_SCHRODINGER;
maxConsistencyIter_ = 1;
}
else if (modelType == DRIFT_DIFFUSION_SCHRODINGER_SLICE) {
physicsModel_ = new PhysicsModelDriftDiffusionSchrodingerSlice(matFileName);
electronDensityEqn_ = ELECTRON_SCHRODINGER;
maxConsistencyIter_ = 1;
}
else {
physicsModel_ = new PhysicsModelDriftDiffusion(matFileName);
}
atc_->useConsistentMassMatrix_(ELECTRON_DENSITY) = true;
rhsMaskIntrinsic_(ELECTRON_TEMPERATURE,SOURCE) = true;
}
ExtrinsicModelDriftDiffusion::~ExtrinsicModelDriftDiffusion()
{
if(continuityIntegrator_) delete continuityIntegrator_;
if(poissonSolver_) delete poissonSolver_;
if(schrodingerSolver_) delete schrodingerSolver_;
if(schrodingerPoissonSolver_) delete schrodingerPoissonSolver_;
}
bool ExtrinsicModelDriftDiffusion::modify(int narg, char **arg)
{
bool match = false;
if (!match) {
match = ExtrinsicModelTwoTemperature::modify(narg, arg);
}
return match;
}
void ExtrinsicModelDriftDiffusion::initialize()
{
ExtrinsicModelTwoTemperature::initialize();
nNodes_ = atc_->num_nodes();
rhs_[ELECTRON_DENSITY].reset(nNodes_,1);
rhs_[ELECTRIC_POTENTIAL].reset(nNodes_,1);
Array2D <bool> rhsMask(NUM_TOTAL_FIELDS,NUM_FLUX);
rhsMask = false;
for (int i = 0; i < NUM_FLUX; i++) {
rhsMask(ELECTRON_DENSITY,i) = atc_->fieldMask_(ELECTRON_DENSITY,i);
}
atc_->set_fixed_nodes();
if (continuityIntegrator_) delete continuityIntegrator_;
if (electronTimeIntegration_ == TimeIntegrator::IMPLICIT) {
continuityIntegrator_ = new FieldImplicitEulerIntegrator(ELECTRON_DENSITY,
physicsModel_, atc_->feEngine_, atc_, rhsMask);
}
else {
continuityIntegrator_ = new FieldExplicitEulerIntegrator(ELECTRON_DENSITY,
physicsModel_, atc_->feEngine_, atc_, rhsMask);
}
atc_->compute_mass_matrix(ELECTRON_DENSITY,physicsModel_);
rhsMask = false;
for (int i = 0; i < NUM_FLUX; i++) {
rhsMask(ELECTRIC_POTENTIAL,i) = atc_->fieldMask_(ELECTRIC_POTENTIAL,i);
}
int type = ATC::LinearSolver::ITERATIVE_SOLVE_SYMMETRIC;
if (poissonSolverType_ == DIRECT) {
type = ATC::LinearSolver::DIRECT_SOLVE;
}
if (poissonSolver_) delete poissonSolver_;
poissonSolver_ = new PoissonSolver(ELECTRIC_POTENTIAL,
physicsModel_, atc_->feEngine_, atc_->prescribedDataMgr_, atc_,
rhsMask,type, true);
poissonSolver_->initialize();
if ( electronDensityEqn_ == ELECTRON_SCHRODINGER ) {
if ( schrodingerSolver_ ) delete schrodingerSolver_;
if ( oneD_ ) {
EfHistory_.reset(oneDslices_.size(),2);
schrodingerSolver_ = new SliceSchrodingerSolver(ELECTRON_DENSITY,
physicsModel_, atc_->feEngine_, atc_->prescribedDataMgr_, atc_,
oneDslices_,oneDdxs_);
}
else {
schrodingerSolver_ = new SchrodingerSolver(ELECTRON_DENSITY,
physicsModel_, atc_->feEngine_, atc_->prescribedDataMgr_, atc_);
}
schrodingerSolver_->initialize();
if ( schrodingerPoissonSolver_ ) delete schrodingerPoissonSolver_;
schrodingerPoissonSolver_ = schrodingerPoissonMgr_.initialize(
atc_, schrodingerSolver_, poissonSolver_, physicsModel_);
}
if (electronDensityEqn_ == ELECTRON_SCHRODINGER && !(atc_->is_initialized())) {
((atc_->fields())[ELECTRON_WAVEFUNCTION].set_quantity()).reset(nNodes_,1);
((atc_->fields())[ELECTRON_WAVEFUNCTIONS].set_quantity()).reset(nNodes_,nNodes_);
((atc_->fields())[ELECTRON_WAVEFUNCTION_ENERGIES].set_quantity()).reset(nNodes_,1);
}
#if 0#endif
}
void ExtrinsicModelDriftDiffusion::pre_init_integrate()
{
double dt = atc_->lammpsInterface_->dt();
double time = atc_->time();
int step = atc_->step();
if (step % fluxUpdateFreq_ != 0) return;
atc_->set_fixed_nodes();
atc_->set_sources();
double idt = dt/nsubcycle_;
for (int i = 0; i < nsubcycle_ ; ++i) {
if (electronDensityEqn_ == ELECTRON_CONTINUITY) {
if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_DENSITY) )
continuityIntegrator_->update(idt,time,atc_->fields_,rhs_);
atc_->set_fixed_nodes();
if (! atc_->prescribedDataMgr_->all_fixed(ELECTRIC_POTENTIAL) )
poissonSolver_->solve(atc_->fields(),rhs_);
}
else if (electronDensityEqn_ == ELECTRON_SCHRODINGER) {
if ( (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_DENSITY) )
|| (! atc_->prescribedDataMgr_->all_fixed(ELECTRIC_POTENTIAL) ) )
schrodingerPoissonSolver_->solve(rhs_,fluxes_);
}
if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_TEMPERATURE)
&& temperatureIntegrator_ ) {
#ifdef ATC_VERBOSE
ATC::LammpsInterface::instance()->stream_msg_once("start temperature integration...",true,false);
#endif
temperatureIntegrator_->update(idt,time,atc_->fields_,rhs_);
#ifdef ATC_VERBOSE
ATC::LammpsInterface::instance()->stream_msg_once(" done",false,true);
#endif
}
atc_->set_fixed_nodes();
}
}
void ExtrinsicModelDriftDiffusion::set_sources(FIELDS & fields, FIELDS & sources)
{
atc_->evaluate_rhs_integral(rhsMaskIntrinsic_, fields,
sources,
atc_->source_integration(), physicsModel_);
}
void ExtrinsicModelDriftDiffusion::output(OUTPUT_LIST & outputData)
{
#ifdef ATC_VERBOSE
#endif
ExtrinsicModelTwoTemperature::output(outputData);
outputData["dot_electron_density"] = & (atc_->dot_field(ELECTRON_DENSITY)).set_quantity();
DENS_MAT & JE = rhs_[ELECTRON_TEMPERATURE].set_quantity();
double totalJouleHeating =JE.sum();
outputData["joule_heating"] = & JE;
atc_->feEngine_->add_global("total_joule_heating",totalJouleHeating);
Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX); rhsMask = false;
rhsMask(ELECTRON_DENSITY,FLUX) = true;
rhsMask(ELECTRIC_POTENTIAL,FLUX) = true;
atc_->compute_flux(rhsMask,atc_->fields_,fluxes_,physicsModel_);
outputData["electron_flux_x"] = & fluxes_[ELECTRON_DENSITY][0];
outputData["electron_flux_y"] = & fluxes_[ELECTRON_DENSITY][1];
outputData["electron_flux_z"] = & fluxes_[ELECTRON_DENSITY][2];
outputData["electric_field_x"] = & fluxes_[ELECTRIC_POTENTIAL][0];
outputData["electric_field_y"] = & fluxes_[ELECTRIC_POTENTIAL][1];
outputData["electric_field_z"] = & fluxes_[ELECTRIC_POTENTIAL][2];
if (electronDensityEqn_ == ELECTRON_SCHRODINGER ) {
SPAR_MAT K;
Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX);
rhsMask = false;
rhsMask(ELECTRON_WAVEFUNCTION,FLUX) = true;
pair<FieldName,FieldName> row_col(ELECTRON_WAVEFUNCTION,
ELECTRON_WAVEFUNCTION);
atc_->feEngine_->compute_tangent_matrix(
rhsMask, row_col, atc_->fields(), physicsModel_,
atc_->element_to_material_map(), K);
phiTotal_.reset(K.nRows(),1);
const DIAG_MAT & inv_dV = (atc_->invNodeVolumes_).quantity();
for (int i = 0; i < K.nRows() ; i++) {
phiTotal_(i,0) = 0.0;
for (int j = 0; j < K.nCols() ; j++) {
phiTotal_(i,0) += K(i,j);
}
phiTotal_(i,0) *= inv_dV(i,i);
}
outputData["V_total"] = & phiTotal_;
}
double nSum = ((atc_->field(ELECTRON_DENSITY)).quantity()).col_sum();
atc_->feEngine_->add_global("total_electron_density",nSum);
#ifdef ATC_VERBOSE
#endif
}
int ExtrinsicModelDriftDiffusion::size_vector(int intrinsicSize)
{
int xSize = ExtrinsicModelTwoTemperature::size_vector(intrinsicSize);
baseSize_ = intrinsicSize + xSize;
xSize += 2;
return xSize;
}
bool ExtrinsicModelDriftDiffusion::compute_vector(int n, double & value)
{
bool match = ExtrinsicModelTwoTemperature::compute_vector(n,value);
if (match) return match;
if (n == baseSize_) {
double nSum = ((atc_->field(ELECTRON_DENSITY)).quantity()).col_sum();
value = nSum;
return true;
}
if (n == baseSize_+1) {
DENS_MAT & JE = rhs_[ELECTRON_TEMPERATURE].set_quantity();
double totalJouleHeating =JE.sum();
value = totalJouleHeating;
return true;
}
return false;
}
ExtrinsicModelDriftDiffusionConvection::ExtrinsicModelDriftDiffusionConvection
(ExtrinsicModelManager * modelManager,
ExtrinsicModelType modelType,
string matFileName) :
ExtrinsicModelDriftDiffusion(modelManager,modelType,matFileName),
cddmPoissonSolver_(NULL),
baseSize_(0)
{
if (physicsModel_) delete physicsModel_;
if (modelType == CONVECTIVE_DRIFT_DIFFUSION_SCHRODINGER) {
physicsModel_ = new PhysicsModelDriftDiffusionConvectionSchrodinger(matFileName);
electronDensityEqn_ = ELECTRON_SCHRODINGER;
}
else {
physicsModel_ = new PhysicsModelDriftDiffusionConvection(matFileName);
}
atc_->useConsistentMassMatrix_(ELECTRON_VELOCITY) = false;
atc_->useConsistentMassMatrix_(ELECTRON_TEMPERATURE) = false;
}
ExtrinsicModelDriftDiffusionConvection::~ExtrinsicModelDriftDiffusionConvection()
{
if (cddmPoissonSolver_) delete cddmPoissonSolver_;
for (vector<LinearSolver * >::const_iterator iter=velocitySolvers_.begin();
iter != velocitySolvers_.end(); iter++)
if (*iter) delete *iter;
}
void ExtrinsicModelDriftDiffusionConvection::initialize()
{
ExtrinsicModelDriftDiffusion::initialize();
nNodes_ = atc_->num_nodes();
nsd_ = atc_->nsd();
rhs_[ELECTRON_VELOCITY].reset(nNodes_,nsd_);
atc_->set_fixed_nodes(); if (cddmPoissonSolver_) delete cddmPoissonSolver_;
Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX);
rhsMask = false;
rhsMask(ELECTRIC_POTENTIAL,FLUX) = true;
pair<FieldName,FieldName> row_col(ELECTRIC_POTENTIAL,ELECTRIC_POTENTIAL);
SPAR_MAT stiffness;
(atc_->feEngine_)->compute_tangent_matrix(rhsMask,row_col, atc_->fields(), physicsModel_,
atc_->element_to_material_map(), stiffness);
const BC_SET & bcs = (atc_->prescribedDataMgr_->bcs(ELECTRIC_POTENTIAL))[0];
cddmPoissonSolver_ = new LinearSolver(stiffness, bcs, poissonSolverType_,
-1, true);
const BCS & velocityBcs = atc_->prescribedDataMgr_->bcs(ELECTRON_VELOCITY);
DENS_MAT velocityRhs(nNodes_,nsd_);
atc_->compute_mass_matrix(ELECTRON_VELOCITY,physicsModel_);
SPAR_MAT & velocityMassMat = (atc_->consistentMassMats_[ELECTRON_VELOCITY]).set_quantity();
for (int i = 0; i < nsd_; i++ ) {
LinearSolver * myVelocitySolver =
new LinearSolver(velocityMassMat, velocityBcs[i],
LinearSolver::AUTO_SOLVE, -1, true);
velocitySolvers_.push_back(myVelocitySolver);
}
}
void ExtrinsicModelDriftDiffusionConvection::pre_init_integrate()
{
double dt = atc_->lammpsInterface_->dt();
double time = atc_->time();
int step = atc_->step();
if (step % fluxUpdateFreq_ != 0) return;
atc_->set_fixed_nodes();
atc_->set_sources();
double idt = dt/nsubcycle_;
for (int i = 0; i < nsubcycle_ ; ++i) {
atc_->compute_mass_matrix(ELECTRON_VELOCITY,physicsModel_);
if (!(atc_->prescribedDataMgr_)->all_fixed(ELECTRON_VELOCITY)) {
Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX);
rhsMask = false;
rhsMask(ELECTRON_VELOCITY,SOURCE) = atc_->fieldMask_(ELECTRON_VELOCITY,SOURCE);
rhsMask(ELECTRON_VELOCITY,FLUX) = atc_->fieldMask_(ELECTRON_VELOCITY,FLUX);
rhsMask(ELECTRON_VELOCITY,OPEN_SOURCE) = atc_->fieldMask_(ELECTRON_VELOCITY,OPEN_SOURCE);
FIELDS rhs;
rhs[ELECTRON_VELOCITY].reset(nNodes_,nsd_);
atc_->compute_rhs_vector(rhsMask, atc_->fields_, rhs, atc_->source_integration(), physicsModel_);
const DENS_MAT & velocityRhs = rhs[ELECTRON_VELOCITY].quantity();
DENS_MAT & velocity = (atc_->field(ELECTRON_VELOCITY)).set_quantity();
for (int j = 0; j < nsd_; ++j) {
if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_VELOCITY,j) ) {
if (atc_->useConsistentMassMatrix_(ELECTRON_VELOCITY)) {
const SPAR_MAT & velocityMassMat = (atc_->consistentMassMats_[ELECTRON_VELOCITY]).quantity();
velocityMassMat.print("VMASS");
CLON_VEC v = column(velocity,j);
const CLON_VEC r = column(velocityRhs,j);
(velocitySolvers_[j])->solve(v,r);
}
else {
atc_->apply_inverse_mass_matrix(velocityRhs,velocity,ELECTRON_VELOCITY);
}
}
}
}
if (electronDensityEqn_ == ELECTRON_CONTINUITY) {
Array2D <bool> rhsMask(NUM_FIELDS,NUM_FLUX);
rhsMask = false;
rhsMask(ELECTRON_DENSITY,FLUX) = atc_->fieldMask_(ELECTRON_DENSITY,FLUX);
rhsMask(ELECTRON_DENSITY,SOURCE) = atc_->fieldMask_(ELECTRON_DENSITY,SOURCE);
rhsMask(ELECTRON_DENSITY,PRESCRIBED_SOURCE) = atc_->fieldMask_(ELECTRON_DENSITY,PRESCRIBED_SOURCE);
FIELDS rhs;
rhs[ELECTRON_DENSITY].reset(nNodes_,1);
atc_->compute_rhs_vector(rhsMask, atc_->fields_, rhs, atc_->source_integration(), physicsModel_);
if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_DENSITY) )
continuityIntegrator_->update(idt,time,atc_->fields_,rhs);
atc_->set_fixed_nodes();
if (! atc_->prescribedDataMgr_->all_fixed(ELECTRIC_POTENTIAL) ) {
rhsMask = false;
rhsMask(ELECTRIC_POTENTIAL,SOURCE) = atc_->fieldMask_(ELECTRIC_POTENTIAL,SOURCE);
rhsMask(ELECTRIC_POTENTIAL,PRESCRIBED_SOURCE) = atc_->fieldMask_(ELECTRIC_POTENTIAL,PRESCRIBED_SOURCE);
rhs[ELECTRIC_POTENTIAL].reset(nNodes_,1);
atc_->compute_rhs_vector(rhsMask, atc_->fields_, rhs, atc_->source_integration(), physicsModel_);
CLON_VEC x =column((atc_->field(ELECTRIC_POTENTIAL)).set_quantity(),0);
const CLON_VEC r =column(rhs[ELECTRIC_POTENTIAL].quantity(),0);
cddmPoissonSolver_->solve(x,r);
}
}
else if (electronDensityEqn_ == ELECTRON_SCHRODINGER) {
schrodingerPoissonSolver_->solve(rhs_,fluxes_);
}
atc_->set_fixed_nodes();
atc_->compute_mass_matrix(ELECTRON_TEMPERATURE,physicsModel_);
if (! atc_->prescribedDataMgr_->all_fixed(ELECTRON_TEMPERATURE) ) {
temperatureIntegrator_->update(idt,time,atc_->fields_,rhs_);
}
atc_->set_fixed_nodes();
}
}
void ExtrinsicModelDriftDiffusionConvection::output(OUTPUT_LIST & outputData)
{
ExtrinsicModelDriftDiffusion::output(outputData);
outputData["joule_heating"] = & (atc_->extrinsic_source(TEMPERATURE)).set_quantity();
DENS_MAT nodalKineticEnergy;
compute_nodal_kinetic_energy(nodalKineticEnergy);
double kineticEnergy = nodalKineticEnergy.sum();
atc_->feEngine_->add_global("total_electron_kinetic_energy",kineticEnergy);
}
int ExtrinsicModelDriftDiffusionConvection::size_vector(int intrinsicSize)
{
int xSize = ExtrinsicModelDriftDiffusion::size_vector(intrinsicSize);
baseSize_ = intrinsicSize + xSize;
xSize += 1;
return xSize;
}
bool ExtrinsicModelDriftDiffusionConvection::compute_vector(int n, double & value)
{
bool match = ExtrinsicModelDriftDiffusion::compute_vector(n,value);
if (match) return match;
if (n == baseSize_) {
DENS_MAT nodalKineticEnergy;
compute_nodal_kinetic_energy(nodalKineticEnergy);
value = nodalKineticEnergy.sum();
return true;
}
return false;
}
void ExtrinsicModelDriftDiffusionConvection::compute_nodal_kinetic_energy(DENS_MAT & kineticEnergy)
{
DENS_MAT & velocity((atc_->field(ELECTRON_VELOCITY)).set_quantity());
SPAR_MAT & velocityMassMat = (atc_->consistentMassMats_[ELECTRON_VELOCITY]).set_quantity();
kineticEnergy.reset(nNodes_,1);
for (int j = 0; j < nsd_; j++) {
CLON_VEC myVelocity(velocity,CLONE_COL,j);
DENS_MAT velocityMat(nNodes_,1);
for (int i = 0; i < nNodes_; i++)
velocityMat(i,0) = myVelocity(i);
kineticEnergy += velocityMat.mult_by_element(myVelocity);
}
kineticEnergy = 0.5*velocityMassMat*kineticEnergy;
}
};