std::shared_ptr<mpFlow::FEM::Sources<dataType>> mpFlow::FEM::Sources<dataType>::fromConfig( json_value const& config, std::shared_ptr<Ports const> const ports, cudaStream_t const stream) { // function to parse pattern config auto const parsePatternConfig = [=](json_value const& config) -> std::shared_ptr<numeric::Matrix<int>> { if (config.type != json_none) { return numeric::Matrix<int>::fromJsonArray(config, stream); } else { return numeric::Matrix<int>::eye(ports->count, stream); } }; // load excitation and measurement pattern from config or assume standard pattern, if not given auto const drivePattern = parsePatternConfig(config["drivePattern"]); auto const measurementPattern = parsePatternConfig(config["measurementPattern"]); // read out currents std::vector<dataType> excitation(drivePattern->cols); if (config["value"].type == json_array) { for (unsigned i = 0; i < drivePattern->cols; ++i) { excitation[i] = config["value"][i].u.dbl; } } else { excitation = std::vector<dataType>(drivePattern->cols, config["value"].type != json_none ? config["value"].u.dbl : dataType(1)); } // create source descriptor auto const sourceType = std::string(config["type"]) == "voltage" ? mpFlow::FEM::Sources<dataType>::Type::Fixed : mpFlow::FEM::Sources<dataType>::Type::Open; auto source = std::make_shared<mpFlow::FEM::Sources<dataType>>(sourceType, excitation, ports, drivePattern, measurementPattern, stream); return source; }
void dumpExcitations(const Everything& e, const char* filename) { const GridInfo& g = e.gInfo; struct excitation { int q,o,u; double dE; double dreal, dimag, dnorm; excitation(int q, int o, int u, double dE, double dreal, double dimag, double dnorm): q(q), o(o), u(u), dE(dE), dreal(dreal), dimag(dimag), dnorm(dnorm){}; inline bool operator<(const excitation& other) const {return dE<other.dE;} void print(FILE* fp) const { fprintf(fp, "%5i %3i %3i %12.5e %12.5e %12.5e %12.5e\n", q, o, u, dE, dreal, dimag, dnorm); } }; std::vector<excitation> excitations; double maxHOMO=-DBL_MAX, minLUMO=DBL_MAX; // maximum (minimum) of all HOMOs (LUMOs) in all qnums int maxHOMOq=0, minLUMOq=0, maxHOMOn=0, minLUMOn=0; //Indices and energies for the indirect gap //Select relevant eigenvals: std::vector<diagMatrix> eigsQP; if(e.exCorr.orbitalDep && e.dump.count(std::make_pair(DumpFreq_End, DumpOrbitalDep))) { //Search for an eigenvalsQP file: string fname = e.dump.getFilename("eigenvalsQP"); FILE* fp = fopen(fname.c_str(), "r"); if(fp) { fclose(fp); eigsQP.resize(e.eInfo.nStates); e.eInfo.read(eigsQP, fname.c_str()); } } const std::vector<diagMatrix>& eigs = eigsQP.size() ? eigsQP : e.eVars.Hsub_eigs; // Integral kernel's for Fermi's golden rule ScalarField r0, r1, r2; nullToZero(r0, g); nullToZero(r1, g); nullToZero(r2, g); applyFunc_r(g, Moments::rn_pow_x, 0, g.R, 1, vector3<>(0.,0.,0.), r0->data()); applyFunc_r(g, Moments::rn_pow_x, 1, g.R, 1, vector3<>(0.,0.,0.), r1->data()); applyFunc_r(g, Moments::rn_pow_x, 2, g.R, 1, vector3<>(0.,0.,0.), r2->data()); //Find and cache all excitations in system (between same qnums) bool insufficientBands = false; for(int q=e.eInfo.qStart; q<e.eInfo.qStop; q++) { //Find local H**O and check band sufficiency: int H**O = e.eInfo.findHOMO(q); if(H**O+1>=e.eInfo.nBands) { insufficientBands=true; break; } //Update global H**O and LUMO of current process: if(eigs[q][H**O] > maxHOMO) { maxHOMOq = q; maxHOMOn = H**O; maxHOMO = eigs[q][H**O]; } if(eigs[q][H**O+1] < minLUMO) { minLUMOq = q; minLUMOn = H**O+1; minLUMO = eigs[q][H**O+1]; } for(int o=H**O; o>=0; o--) { for(int u=(H**O+1); u<e.eInfo.nBands; u++) { complex x = integral(I(e.eVars.C[q].getColumn(u,0))*r0*I(e.eVars.C[q].getColumn(o,0))); complex y = integral(I(e.eVars.C[q].getColumn(u,0))*r1*I(e.eVars.C[q].getColumn(o,0))); complex z = integral(I(e.eVars.C[q].getColumn(u,0))*r2*I(e.eVars.C[q].getColumn(o,0))); vector3<> dreal(x.real(), y.real(),z.real()); vector3<> dimag(x.imag(), y.imag(),z.imag()); vector3<> dnorm(sqrt(x.norm()), sqrt(y.norm()),sqrt(z.norm())); double dE = eigs[q][u]-eigs[q][o]; //Excitation energy excitations.push_back(excitation(q, o, u, dE, dreal.length_squared(), dimag.length_squared(), dnorm.length_squared())); } } } mpiUtil->allReduce(insufficientBands, MPIUtil::ReduceLOr); if(insufficientBands) { logPrintf("Insufficient bands to calculate excited states!\n"); logPrintf("Increase the number of bands (elec-n-bands) and try again!\n"); return; } //Transmit results to head process: if(mpiUtil->isHead()) { excitations.reserve(excitations.size() * mpiUtil->nProcesses()); for(int jProcess=1; jProcess<mpiUtil->nProcesses(); jProcess++) { //Receive data: size_t nExcitations; mpiUtil->recv(nExcitations, jProcess, 0); std::vector<int> msgInt(4 + nExcitations*3); std::vector<double> msgDbl(2 + nExcitations*4); mpiUtil->recv(msgInt.data(), msgInt.size(), jProcess, 1); mpiUtil->recv(msgDbl.data(), msgDbl.size(), jProcess, 2); //Unpack: std::vector<int>::const_iterator intPtr = msgInt.begin(); std::vector<double>::const_iterator dblPtr = msgDbl.begin(); //--- globals: int j_maxHOMOq = *(intPtr++); int j_maxHOMOn = *(intPtr++); double j_maxHOMO = *(dblPtr++); int j_minLUMOq = *(intPtr++); int j_minLUMOn = *(intPtr++); double j_minLUMO = *(dblPtr++); if(j_maxHOMO > maxHOMO) { maxHOMOq=j_maxHOMOq; maxHOMOn=j_maxHOMOn; maxHOMO=j_maxHOMO; } if(j_minLUMO < minLUMO) { minLUMOq=j_minLUMOq; minLUMOn=j_minLUMOn; minLUMO=j_minLUMO; } //--- excitation array: for(size_t iExcitation=0; iExcitation<nExcitations; iExcitation++) { int q = *(intPtr++); int o = *(intPtr++); int u = *(intPtr++); double dE = *(dblPtr++); double dreal = *(dblPtr++); double dimag = *(dblPtr++); double dnorm = *(dblPtr++); excitations.push_back(excitation(q, o, u, dE, dreal, dimag, dnorm)); } } } else { //Pack data: std::vector<int> msgInt; std::vector<double> msgDbl; size_t nExcitations = excitations.size(); msgInt.reserve(4 + nExcitations*3); msgDbl.reserve(2 + nExcitations*4); msgInt.push_back(maxHOMOq); msgInt.push_back(maxHOMOn); msgDbl.push_back(maxHOMO); msgInt.push_back(minLUMOq); msgInt.push_back(minLUMOn); msgDbl.push_back(minLUMO); for(const excitation& e: excitations) { msgInt.push_back(e.q); msgInt.push_back(e.o); msgInt.push_back(e.u); msgDbl.push_back(e.dE); msgDbl.push_back(e.dreal); msgDbl.push_back(e.dimag); msgDbl.push_back(e.dnorm); } //Send data: mpiUtil->send(nExcitations, 0, 0); mpiUtil->send(msgInt.data(), msgInt.size(), 0, 1); mpiUtil->send(msgDbl.data(), msgDbl.size(), 0, 2); } //Process and print excitations: if(!mpiUtil->isHead()) return; FILE* fp = fopen(filename, "w"); if(!fp) die("Error opening %s for writing.\n", filename); std::sort(excitations.begin(), excitations.end()); const excitation& opt = excitations.front(); fprintf(fp, "Using %s eigenvalues. H**O: %.5f LUMO: %.5f \n", eigsQP.size() ? "discontinuity-corrected QP" : "KS", maxHOMO, minLUMO); fprintf(fp, "Optical (direct) gap: %.5e (from n = %i to %i in qnum = %i)\n", opt.dE, opt.o, opt.u, opt.q); fprintf(fp, "Indirect gap: %.5e (from (%i, %i) to (%i, %i))\n\n", minLUMO-maxHOMO, maxHOMOq, maxHOMOn, minLUMOq, minLUMOn); fprintf(fp, "Optical excitation energies and corresponding electric dipole transition strengths\n"); fprintf(fp, "qnum i f dE |<psi1|r|psi2>|^2 (real, imag, norm)\n"); for(const excitation& e: excitations) e.print(fp); fclose(fp); }