#include "Material.h" #include "ATC_Transfer.h" #include "LammpsInterface.h" #include "ElectronChargeDensity.h" #include "ElectronHeatCapacity.h" #include "ElectronHeatFlux.h" #include "ElectronPhononExchange.h" #include "ElectronDragPower.h" #include "Stress.h" #include "ViscousStress.h" #include "BodyForce.h" #include "ElectronFlux.h" #include #include #include using ATC_Utility::command_line; using ATC_Utility::str2dbl; using ATC_Utility::str2int; using std::stringstream; using std::set; using std::fstream; using std::string; using std::vector; namespace ATC { Material::Material() : rhoCp_(0), heatCapacity_(0), electronHeatCapacity_(NULL), massDensity_(0), heatConductivity_(0), electronHeatFlux_(NULL), stress_(NULL), viscousStress_(NULL), bodyForce_(NULL), electronPhononExchange_(NULL), electronDragPower_(NULL), electronFlux_(NULL), permittivity_(1.), invEffectiveMass_(1.), electronEquilibriumDensity_(0), electronRecombinationInvTau_(0), electronChargeDensity_(NULL) { } //-------------------------------------------------------------- // Constructor (parser) //-------------------------------------------------------------- // Example: // material Cu // heat_capacity constant // capacity 1.0 // end // heat_flux linear // conductivity 1.0 // end // electron_heat_flux linear // conductivity 1.0 // end // electron_heat_capacity linear // capacity 1.0 // end // electron_phonon_exchange linear // coefficient 0.1 // end // end Material::Material(string & tag, fstream &fileId) : tag_(tag), rhoCp_(0), heatCapacity_(0), electronHeatCapacity_(NULL), massDensity_(0), heatConductivity_(0), electronHeatFlux_(NULL), stress_(NULL), viscousStress_(NULL), bodyForce_(NULL), electronPhononExchange_(NULL), electronDragPower_(NULL), electronFlux_(NULL), permittivity_(1.), invEffectiveMass_(1.), electronEquilibriumDensity_(0), electronRecombinationInvTau_(0), electronChargeDensity_(NULL) { linearFlux_.reset(NUM_FIELDS); linearFlux_ = false; linearSource_.reset(NUM_FIELDS); linearSource_ = true; constantDensity_.reset(NUM_FIELDS); constantDensity_ = false; rhoCp_ = ATC::LammpsInterface::instance()->heat_capacity(); parameters_["heat_capacity"] = rhoCp_; heatCapacity_ = rhoCp_; registry_.insert("heat_capacity"); registry_.insert("thermal_energy"); constantDensity_(TEMPERATURE) = true; constantDensity_(DISPLACEMENT) = true; constantDensity_(VELOCITY) = true; electronDragPower_ = new ElectronDragPower(); vector line; while(fileId.good()) { command_line(fileId, line); if (line.size() == 0) continue; if (line.size() == 1) { if (line[0] == "end") { return; } } if (line[0] == "heat_capacity") { // over-ride default registry_. insert("heat_capacity"); registry_. insert("thermal_energy"); if (line[1] == "constant") { while(fileId.good()) { command_line(fileId, line); if (line.size() == 0) continue; if (line[0] == "end") break; double value = str2dbl(line[1]); if (line[0] == "capacity") { heatCapacity_ = value; parameters_["heat_capacity"] = heatCapacity_; } } } } else if (line[0] == "heat_flux") { registry_. insert("heat_flux"); if (line[1] == "linear") { linearFlux_(TEMPERATURE) = true; while(fileId.good()) { command_line(fileId, line); if (line.size() == 0) continue; if (line[0] == "end") break; double value = str2dbl(line[1]); if (line[0] == "conductivity") { heatConductivity_ = value; } } } } else if (line[0] == "electron_heat_flux") { registry_. insert("electron_heat_flux"); if (line[1] == "null") { linearFlux_(ELECTRON_TEMPERATURE) = true; if (electronHeatFlux_) delete electronHeatFlux_; electronHeatFlux_ = new ElectronHeatFlux(); } else if (line[1] == "linear") { linearFlux_(ELECTRON_TEMPERATURE) = true; if (electronHeatCapacity_) { if (electronHeatFlux_) delete electronHeatFlux_; electronHeatFlux_ = new ElectronHeatFluxLinear(fileId, parameters_,electronHeatCapacity_); } else { if (electronHeatFlux_) delete electronHeatFlux_; electronHeatFlux_ = new ElectronHeatFluxLinear(fileId, parameters_); } } else if (line[1] == "power_law") { if (electronHeatCapacity_) { if (electronHeatFlux_) delete electronHeatFlux_; electronHeatFlux_ = new ElectronHeatFluxPowerLaw(fileId, parameters_,electronHeatCapacity_); } else { if (electronHeatFlux_) delete electronHeatFlux_; electronHeatFlux_ = new ElectronHeatFluxPowerLaw(fileId, parameters_); } } else if (line[1] == "thermopower") { if (! electronFlux_) { throw ATC_Error( "for thermopower please define electron_flux before electron_heat_flux"); } if (electronHeatFlux_) delete electronHeatFlux_; electronHeatFlux_ = new ElectronHeatFluxThermopower(fileId, parameters_, electronFlux_); } } else if (line[0] == "electron_heat_capacity") { registry_. insert("electron_heat_capacity"); registry_. insert("electron_thermal_energy"); if (line[1] == "constant") { if ((line.size() == 3) && (line[2] == "no_density")) { if (electronHeatCapacity_) delete electronHeatCapacity_; electronHeatCapacity_ = new ElectronHeatCapacityConstantAddDensity(fileId, parameters_, this); } else { constantDensity_(ELECTRON_TEMPERATURE) = true; if (electronHeatCapacity_) delete electronHeatCapacity_; electronHeatCapacity_ = new ElectronHeatCapacityConstant(fileId, parameters_); } } else if (line[1] == "linear") { if ((line.size() == 3) && line[2] == "no_density") { if (electronHeatCapacity_) delete electronHeatCapacity_; electronHeatCapacity_ = new ElectronHeatCapacityLinearAddDensity(fileId, parameters_, this); } else { if (electronHeatCapacity_) delete electronHeatCapacity_; electronHeatCapacity_ = new ElectronHeatCapacityLinear(fileId, parameters_); } } } else if (line[0] == "electron_phonon_exchange") { registry_. insert("electron_phonon_exchange"); if (line[1] == "null") { if (electronPhononExchange_) delete electronPhononExchange_; electronPhononExchange_ = new ElectronPhononExchange(); } else if (line[1] == "linear") { if (electronPhononExchange_) delete electronPhononExchange_; electronPhononExchange_ = new ElectronPhononExchangeLinear(fileId, parameters_); } else if (line[1] == "power_law") { linearSource_(TEMPERATURE) = false; linearSource_(ELECTRON_TEMPERATURE) = false; if (electronPhononExchange_) delete electronPhononExchange_; electronPhononExchange_ = new ElectronPhononExchangePowerLaw(fileId, parameters_); } else if (line[1] == "hertel") { linearSource_(TEMPERATURE) = false; linearSource_(ELECTRON_TEMPERATURE) = false; if (electronPhononExchange_) delete electronPhononExchange_; electronPhononExchange_ = new ElectronPhononExchangeHertel(fileId,parameters_,this); } } else if (line[0] == "mass_density") { // over-ride default registry_. insert("mass_density"); registry_. insert("kinetic_energy"); if (line.size() == 1 ) { // try to calculate from lattice massDensity_ = LammpsInterface::instance()->mass_density(); parameters_["mass_density"] = massDensity_; stringstream ss; ss << "computed mass density : " << massDensity_ ; ATC::LammpsInterface::instance()->print_msg_once(ss.str()); } else if (line[1] == "basis") { while(fileId.good()) { command_line(fileId, line); if (line.size() == 0) continue; if (line[0] == "end") break; int n = line.size(); int* numPerType = new int[n]; for (int i = 0; i < n; i++) { numPerType[i] = str2int(line[i]); } massDensity_ = LammpsInterface::instance()->mass_density(numPerType); delete [] numPerType; parameters_["mass_density"] = massDensity_; stringstream ss; ss << "computed mass density (from given basis) : " << massDensity_ ; ATC::LammpsInterface::instance()->print_msg_once(ss.str()); } } else if (line[1] == "constant") { while(fileId.good()) { command_line(fileId, line); if (line.size() == 0) continue; if (line[0] == "end") break; double value = str2dbl(line[1]); if (line[0] == "density") { massDensity_ = value; parameters_["mass_density"] = massDensity_; } } } } else if (line[0] == "stress") { registry_. insert("stress"); registry_. insert("elastic_energy"); if (line[1] == "linear") { linearFlux_(VELOCITY) = true; linearFlux_(DISPLACEMENT) = true; if (stress_) delete stress_; stress_ = new StressLinearElastic(fileId); } else if (line[1] == "cubic") { linearFlux_(VELOCITY) = true; linearFlux_(DISPLACEMENT) = true; if (stress_) delete stress_; stress_ = new StressCubicElastic(fileId); } else if (line[1] == "damped_cubic") { linearFlux_(VELOCITY) = true; linearFlux_(DISPLACEMENT) = true; if (stress_) delete stress_; stress_ = new StressCubicElasticDamped(fileId); } else if (line[1] == "cauchy-born") { CbData cb; LammpsInterface *lmp = LammpsInterface::instance(); lmp->lattice(cb.cell_vectors, cb.basis_vectors); cb.inv_atom_volume = 1.0 / lmp->volume_per_atom(); cb.e2mvv = 1.0 / lmp->mvv2e(); cb.boltzmann = lmp->boltz(); cb.atom_mass = lmp->atom_mass(1); if (stress_) delete stress_; stress_ = new StressCauchyBorn(fileId, cb); } } else if (line[0] == "viscous_stress") { registry_.insert("viscous_stress"); if (line[1] == "constant") { linearFlux_(VELOCITY) = true; if (viscousStress_) delete viscousStress_; viscousStress_ = new ViscousStressConstant(fileId); } } else if (line[0] == "body_force") { registry_. insert("body_force"); if (line.size() > 1) { if (line[1] == "electric_field") { if (bodyForce_) delete bodyForce_; bodyForce_ = new BodyForceElectricField(fileId,parameters_); } else if (line[1] == "viscous") { if (bodyForce_) delete bodyForce_; bodyForce_ = new BodyForceViscous(fileId,parameters_); } else { if (bodyForce_) delete bodyForce_; bodyForce_ = new BodyForce(); } } else { if (bodyForce_) delete bodyForce_; bodyForce_ = new BodyForce(); } } else if (line[0] == "electron_flux") { registry_. insert("electron_flux"); if (line[1] == "null") { linearFlux_(ELECTRON_DENSITY) = true; if (electronFlux_) delete electronFlux_; electronFlux_ = new ElectronFlux(); } else if (line[1] == "linear") { linearFlux_(ELECTRON_DENSITY) = true; if (electronFlux_) delete electronFlux_; electronFlux_ = new ElectronFluxLinear(fileId, parameters_); } else if (line[1] == "thermopower") { if (electronFlux_) delete electronFlux_; electronFlux_ = new ElectronFluxThermopower(fileId, parameters_); } else if (line[1] == "convection") { if (electronFlux_) delete electronFlux_; electronFlux_ = new ElectronFluxConvection(fileId, parameters_); } } else if (line[0] == "electric_field") { registry_. insert("electric_field"); registry_. insert("electric_displacement"); if (line[1] == "linear") { linearFlux_(ELECTRIC_POTENTIAL) = true; while(fileId.good()) { command_line(fileId, line); if (line.size() == 0) continue; if (line[0] == "end") break; if (line[0] == "permittivity") { // if no value given use lammps dielectric constant if (line.size() == 1 ) { permittivity_ = LammpsInterface::instance()->dielectric(); } else { double value = str2dbl(line[1]); permittivity_ = value; } // convert relative permitivity (dielectric) to abs internal units stringstream ss; ss << "permittivity : " << permittivity_ ; permittivity_ *= LammpsInterface::instance()->epsilon0(); ss << " -> " << permittivity_ ; LammpsInterface::UnitsType utype = LammpsInterface::instance()->units_style(); if ( utype != LammpsInterface::REAL && utype != LammpsInterface::METAL) { ATC::LammpsInterface::instance()->print_msg_once("WARNING: must use a unit system where: [Energy/force] = [Length] and [charge] = e"); // note this is so that: perm0/e = 1 / (Epotential_units * Length) // our charge densities are multiples of the elemental charge } parameters_["permittivity"] = permittivity_; } } } } else if (line[0] == "effective_mass") { registry_. insert("inv_effective_mass"); if (line[1] == "constant") { linearFlux_(ELECTRON_WAVEFUNCTION) = true; while(fileId.good()) { command_line(fileId, line); if (line.size() == 0) continue; if (line[0] == "end") break; if (line[0] == "inv_effective_mass") { double value = str2dbl(line[1]); invEffectiveMass_ = value; // 1/m* = inv_eff_mass/m_e // convert to hbar^2 / 2 / m* / e //double hbar = LammpsInterface::instance()->hbar(); //invEffectiveMass_ *= 0.5*hbar*hbar; // m_e in units [eV-ps^2/A^2] : 5.68562958414706e-32 double scale = 3.80998192145007; // units [V A^2] invEffectiveMass_ *= scale; parameters_["inverse_effective_mass"] = invEffectiveMass_; } } } } else if (line[0] == "electron_drag") { registry_.insert("electron_drag_power"); registry_.insert("electron_drag_coefficient"); if (line[1] == "null") { if (electronDragPower_) delete electronDragPower_; electronDragPower_ = new ElectronDragPower(); } else if (line[1] == "linear") { if (electronDragPower_) delete electronDragPower_; electronDragPower_ = new ElectronDragPowerLinear(fileId, parameters_, this); } } else if (line[0] == "electron_recombination") { registry_. insert("electron_recombination"); if (line[1] == "linear") { while(fileId.good()) { command_line(fileId, line); if (line.size() == 0) continue; if (line[0] == "end") break; double value = str2dbl(line[1]); if (line[0] == "inv_relaxation_time") { electronRecombinationInvTau_ = value; parameters_["inv_relaxation_time"] = electronRecombinationInvTau_; } else if (line[0] == "equilibrium_carrier_density") { electronEquilibriumDensity_ = value; parameters_["equilibrium_carrier_density"] = electronEquilibriumDensity_; } } } } else if (line[0] == "electron_density") { // density is converted to charge registry_. insert("electron_charge_density"); if (line[1] == "null") { if (electronChargeDensity_) delete electronChargeDensity_; electronChargeDensity_ = new ElectronChargeDensity(); } else if (line[1] == "linear") { linearSource_(ELECTRIC_POTENTIAL) = false; if (electronChargeDensity_) delete electronChargeDensity_; electronChargeDensity_ = new ElectronChargeDensityLinear(fileId, parameters_); } else if (line[1] == "interpolation") { linearSource_(ELECTRIC_POTENTIAL) = false; if (electronChargeDensity_) delete electronChargeDensity_; electronChargeDensity_ = new ElectronChargeDensityInterpolation(fileId, parameters_); } else if (line[1] == "exponential") { linearSource_(ELECTRIC_POTENTIAL) = false; if (electronChargeDensity_) delete electronChargeDensity_; electronChargeDensity_ = new ElectronChargeDensityExponential(fileId, parameters_); } else if (line[1] == "fermi_dirac") { registry_. insert("band_edge_potential"); //linearSource_(ELECTRIC_POTENTIAL) = false; // treated as constant if (electronChargeDensity_) delete electronChargeDensity_; electronChargeDensity_ = new ElectronChargeDensityFermiDirac(fileId, parameters_); } else { throw ATC_Error("unrecognized material function type: "+line[0]+" - "+line[1]); } } else { throw ATC_Error( "unrecognized material function: "+line[0]); } } } //-------------------------------------------------------------------- Material::~Material() { if (electronDragPower_) delete electronDragPower_; if (electronChargeDensity_) delete electronChargeDensity_; if (electronHeatCapacity_) delete electronHeatCapacity_; if (electronHeatFlux_) delete electronHeatFlux_; if (electronFlux_) delete electronFlux_; if (stress_) delete stress_; if (viscousStress_) delete viscousStress_; if (bodyForce_) delete bodyForce_; if (electronPhononExchange_) delete electronPhononExchange_; } //--------------------------------------------------------------------- void Material::initialize(){if (stress_) stress_->initialize();} void Material::heat_capacity( const FIELD_MATS & fields, DENS_MAT & capacity) const { const DENS_MAT & T = (fields.find(TEMPERATURE))->second; int nNodes = T.nRows(); capacity.reset(nNodes,1); capacity = heatCapacity_; }; //--------------------------------------------------------------------- void Material::thermal_energy( const FIELD_MATS &fields, DENS_MAT &energy) const { const DENS_MAT & T = (fields.find(TEMPERATURE))->second; energy = heatCapacity_ * T; }; //--------------------------------------------------------------------- void Material::electron_heat_capacity( const FIELD_MATS & fields, DENS_MAT & capacity) const { electronHeatCapacity_->electron_heat_capacity(fields,capacity); }; //--------------------------------------------------------------------- void Material::D_electron_heat_capacity( const FIELD_MATS & fields, const GRAD_FIELD_MATS & gradFields, DENS_MAT_VEC & Dcapacity) const { electronHeatCapacity_->D_electron_heat_capacity(fields,gradFields,Dcapacity); }; //--------------------------------------------------------------------- void Material::electron_thermal_energy( const FIELD_MATS &fields, DENS_MAT &energy) const { electronHeatCapacity_->electron_thermal_energy(fields,energy); }; //--------------------------------------------------------------------- void Material::mass_density( const FIELD_MATS &fields, DENS_MAT &density) const { int nNodes = 0; FIELD_MATS::const_iterator field = fields.find(MASS_DENSITY); if (field != fields.end()) { const DENS_MAT & d = field->second; nNodes = d.nRows(); } else { FIELD_MATS::const_iterator field = fields.find(VELOCITY); if (field != fields.end()) { const DENS_MAT & v = field->second; nNodes = v.nRows(); } } density.reset(nNodes,1); density = massDensity_; }; //--------------------------------------------------------------------- void Material::electron_mass_density( const FIELD_MATS &fields, DENS_MAT &density) const { int nNodes = 0; FIELD_MATS::const_iterator field = fields.find(ELECTRON_DENSITY); //if (field != fields.end()) { const DENS_MAT & d = field->second; nNodes = d.nRows(); //} density.reset(nNodes,1); inv_effective_mass(fields,density); density = d.div_by_element(density); }; //--------------------------------------------------------------------- void Material::kinetic_energy( const FIELD_MATS &fields, DENS_MAT &energy) const { FIELD_MATS::const_iterator field = fields.find(VELOCITY); if (field != fields.end()) { const DENS_MAT & v = field->second; energy = 0.5*massDensity_*v; energy *= v; } else { energy = 0.; } }; //--------------------------------------------------------------------- void Material::permittivity( const FIELD_MATS &fields, DENS_MAT &density) const { const DENS_MAT & phi = (fields.find(ELECTRIC_POTENTIAL))->second; int nNodes = phi.nRows(); density.reset(nNodes,1); density = permittivity_; }; //--------------------------------------------------------------------- void Material::band_edge_potential( const FIELD_MATS &fields, DENS_MAT &density) const { electronChargeDensity_->band_edge_potential(fields,density); }; //--------------------------------------------------------------------- void Material::inv_effective_mass( const FIELD_MATS &fields, DENS_MAT &density) const { const DENS_MAT & phi = (fields.find(ELECTRON_DENSITY))->second; int nNodes = phi.nRows(); density.reset(nNodes,1); density = invEffectiveMass_; }; //--------------------------------------------------------------------- void Material::heat_flux( const FIELD_MATS & fields, const GRAD_FIELD_MATS & gradFields, DENS_MAT_VEC & flux) const { const DENS_MAT_VEC & dT = (gradFields.find(TEMPERATURE))->second; flux[0] = -heatConductivity_* dT[0]; flux[1] = -heatConductivity_* dT[1]; flux[2] = -heatConductivity_* dT[2]; } //--------------------------------------------------------------------- void Material::electron_heat_flux( const FIELD_MATS & fields, const GRAD_FIELD_MATS & gradFields, DENS_MAT_VEC & flux) const { electronHeatFlux_->electron_heat_flux(fields,gradFields,flux); } //--------------------------------------------------------------------- void Material::electron_heat_convection( const FIELD_MATS & fields, DENS_MAT_VEC & flux) const { electronHeatFlux_->electron_heat_convection(fields,flux); } //--------------------------------------------------------------------- bool Material::electron_phonon_exchange( const FIELD_MATS & fields, DENS_MAT & flux) const { return electronPhononExchange_->electron_phonon_exchange(fields,flux); } //--------------------------------------------------------------------- void Material::electron_drag_velocity_coefficient( const FIELD_MATS &fields, DENS_MAT & dragCoef) const { electronDragPower_->electron_drag_velocity_coefficient(fields,dragCoef); } //--------------------------------------------------------------------- bool Material::electron_drag_power( const FIELD_MATS &fields, const GRAD_FIELD_MATS &gradFields, DENS_MAT & power) const { return electronDragPower_->electron_drag_power(fields,gradFields,power); } //--------------------------------------------------------------------- bool Material::electron_recombination( const FIELD_MATS &fields, const GRAD_FIELD_MATS &gradFields, DENS_MAT & recombination) const { // 1/tau (n - n0) const DENS_MAT & n = (fields.find(ELECTRON_DENSITY))->second; recombination = n; recombination -= electronEquilibriumDensity_; recombination *= -electronRecombinationInvTau_; return true; } //--------------------------------------------------------------------- bool Material::electron_charge_density( const FIELD_MATS &fields, DENS_MAT & density) const { return electronChargeDensity_->electron_charge_density(fields,density); }; //--------------------------------------------------------------------- void Material::D_electron_charge_density(const FieldName fieldName, const FIELD_MATS &fields, DENS_MAT & D_density) const { electronChargeDensity_->D_electron_charge_density(fieldName,fields,D_density); }; //--------------------------------------------------------------------- bool Material::body_force( const FIELD_MATS &fields, DENS_MAT & density) const { return bodyForce_->body_force(fields,density); }; //--------------------------------------------------------------------- void Material::stress( const FIELD_MATS & fields, const GRAD_FIELD_MATS & gradFields, DENS_MAT_VEC & stress) const { stress_->stress(fields,gradFields,stress); } //--------------------------------------------------------------------- void Material::elastic_energy( const FIELD_MATS & fields, const GRAD_FIELD_MATS & gradFields, DENS_MAT & energy) const { stress_->elastic_energy(fields,gradFields,energy); } //--------------------------------------------------------------------- void Material::viscous_stress( const FIELD_MATS & fields, const GRAD_FIELD_MATS & gradFields, DENS_MAT_VEC & stress) const { viscousStress_->viscous_stress(fields,gradFields,stress); } //--------------------------------------------------------------------- void Material::viscosity( const FIELD_MATS &fields, DENS_MAT &coefs) const { viscousStress_->viscosity(fields,coefs); } //--------------------------------------------------------------------- void Material::electron_flux( const FIELD_MATS &fields, const GRAD_FIELD_MATS &gradFields, DENS_MAT_VEC &flux) const { electronFlux_->electron_flux(fields,gradFields,flux); } //--------------------------------------------------------------------- void Material::electric_field( const FIELD_MATS &fields, const GRAD_FIELD_MATS &gradFields, DENS_MAT_VEC &flux) const { // E = - grad \phi const DENS_MAT_VEC & dphi = (gradFields.find(ELECTRIC_POTENTIAL))->second; flux[0] = -1.0* dphi[0]; flux[1] = -1.0* dphi[1]; flux[2] = -1.0* dphi[2]; } //--------------------------------------------------------------------- void Material::electric_displacement( const FIELD_MATS &fields, const GRAD_FIELD_MATS &gradFields, DENS_MAT_VEC &flux) const { // D = - permitivity grad \phi const DENS_MAT_VEC & dphi = (gradFields.find(ELECTRIC_POTENTIAL))->second; flux[0] = -permittivity_* dphi[0]; flux[1] = -permittivity_* dphi[1]; flux[2] = -permittivity_* dphi[2]; } //--------------------------------------------------------------------- } // end namespace