Example #1
0
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);
}