1 #ifndef ROL_DIODECIRCUIT_HPP 2 #define ROL_DIODECIRCUIT_HPP 41 typedef typename vector::size_type
uint;
47 Teuchos::RCP<std::vector<Real> >
Imeas_;
49 Teuchos::RCP<std::vector<Real> >
Vsrc_;
59 Teuchos::RCP<const vector>
getVector(
const V& x ) {
60 using Teuchos::dyn_cast;
using Teuchos::getConst;
62 return dyn_cast<
const STDV>(getConst(x)).
getVector();
64 catch (std::exception &e) {
66 return dyn_cast<
const PSV>(getConst(x)).
getVector();
68 catch (std::exception &e) {
69 return dyn_cast<
const DSV>(getConst(x)).
getVector();
75 using Teuchos::dyn_cast;
79 catch (std::exception &e) {
83 catch (std::exception &e) {
98 Objective_DiodeCircuit(Real Vth, Real Vsrc_min, Real Vsrc_max, Real Vsrc_step, Real true_Is, Real true_Rs,
bool lambertw, Real noise,
bool use_adjoint,
int use_hessvec){
101 use_adjoint_ = use_adjoint;
102 use_hessvec_ = use_hessvec;
103 int n = (Vsrc_max-Vsrc_min)/Vsrc_step + 1;
104 Vsrc_ = Teuchos::rcp(
new std::vector<Real>(n,0.0));
105 Imeas_ = Teuchos::rcp(
new std::vector<Real>(n,0.0));
106 std::ofstream output (
"Measurements.dat");
107 Real left = 0.0; Real right = 1.0;
110 std::cout <<
"Generating data using Lambert-W function." << std::endl;
111 for(
int i=0;i<n;i++){
112 (*Vsrc_)[i] = Vsrc_min+i*Vsrc_step;
115 (*Imeas_)[i] += noise*pow(10,
int(log10((*Imeas_)[i])))*(( (Real)rand() / (Real)RAND_MAX ) * (right - left) + left);
118 if(output.is_open()){
119 output << std::setprecision(8) << std::scientific << (*Vsrc_)[i] <<
" " << (*Imeas_)[i] <<
"\n";
125 std::cout <<
"Generating data using Newton's method." << std::endl;
126 for(
int i=0;i<n;i++){
127 (*Vsrc_)[i] = Vsrc_min+i*Vsrc_step;
129 (*Imeas_)[i] =
Newton(I0,Vsrc_min+i*Vsrc_step,true_Is,true_Rs);
131 (*Imeas_)[i] += noise*pow(10,
int(log10((*Imeas_)[i])))*(( (Real)rand() / (Real)RAND_MAX ) * (right - left) + left);
134 if(output.is_open()){
135 output << std::setprecision(8) << std::scientific << (*Vsrc_)[i] <<
" " << (*Imeas_)[i] <<
"\n";
154 use_adjoint_ = use_adjoint;
155 use_hessvec_ = use_hessvec;
158 for(
int k=0;std::getline(input_file,line);++k){dim=k;}
160 input_file.seekg(0,std::ios::beg);
161 Vsrc_ = Teuchos::rcp(
new std::vector<Real>(dim,0.0));
162 Imeas_ = Teuchos::rcp(
new std::vector<Real>(dim,0.0));
164 std::cout <<
"Using input file to generate data." <<
"\n";
165 for(
int i=0;i<dim;i++){
169 (*Imeas_)[i] = Imeas;
190 Real
diode(
const Real I,
const Real Vsrc,
const Real Is,
const Real Rs){
191 return I-Is*(exp((Vsrc-I*Rs)/Vth_)-1);
195 Real
diodeI(
const Real I,
const Real Vsrc,
const Real Is,
const Real Rs){
196 return 1+Is*exp((Vsrc-I*Rs)/Vth_)*(Rs/
Vth_);
200 Real
diodeIs(
const Real I,
const Real Vsrc,
const Real Is,
const Real Rs){
201 return 1-exp((Vsrc-I*Rs)/Vth_);
205 Real
diodeRs(
const Real I,
const Real Vsrc,
const Real Is,
const Real Rs){
206 return Is*exp((Vsrc-I*Rs)/Vth_)*(I/
Vth_);
210 Real
diodeII(
const Real I,
const Real Vsrc,
const Real Is,
const Real Rs){
211 return -Is*exp((Vsrc-I*Rs)/Vth_)*(Rs/
Vth_)*(Rs/Vth_);
215 Real
diodeIIs(
const Real I,
const Real Vsrc,
const Real Is,
const Real Rs){
216 return exp((Vsrc-I*Rs)/Vth_)*(Rs/
Vth_);
220 Real
diodeIRs(
const Real I,
const Real Vsrc,
const Real Is,
const Real Rs){
221 return (Is/Vth_)*exp((Vsrc-I*Rs)/Vth_)*(1-(I*Rs)/Vth_);
225 Real
diodeIsIs(
const Real I,
const Real Vsrc,
const Real Is,
const Real Rs){
230 Real
diodeIsRs(
const Real I,
const Real Vsrc,
const Real Is,
const Real Rs){
231 return exp((Vsrc-I*Rs)/Vth_)*(I/
Vth_);
235 Real
diodeRsRs(
const Real I,
const Real Vsrc,
const Real Is,
const Real Rs){
236 return -Is*exp((Vsrc-I*Rs)/Vth_)*(I/
Vth_)*(I/Vth_);
246 Real
Newton(
const Real I,
const Real Vsrc,
const Real Is,
const Real Rs){
251 Real fval =
diode(IN,Vsrc,Is,Rs);
256 for (
int i = 0; i < MAXIT; i++ ) {
257 if ( std::fabs(fval) < TOL ) {
261 dfval =
diodeI(IN,Vsrc,Is,Rs);
262 if( std::fabs(dfval) < EPS ){
263 std::cout <<
"denominator is too small" << std::endl;
268 IN_tmp = IN - alpha*fval/dfval;
269 fval_tmp =
diode(IN_tmp,Vsrc,Is,Rs);
270 while ( std::fabs(fval_tmp) >= (1.0-1.e-4*alpha)*std::fabs(fval) ) {
272 IN_tmp = IN - alpha*fval/dfval;
273 fval_tmp =
diode(IN_tmp,Vsrc,Is,Rs);
274 if ( alpha < std::sqrt(EPS) ) {
319 void lambertw(Real x, Real &w,
int &ierr, Real &xi){
321 const Real turnpt = -exp(-1.), c1 = 1.5, c2 = .75;
322 Real r, r2, r3, s, mach_eps, relerr = 1., diff;
333 if( x == 0. )
return;
334 if( x < (1-c2) ) w = x*(1.-x + c1*x*x);
340 w = x*(1.0-x + c1*x*x);
341 xi = log(1.0-x + c1*x*x) - w;
345 if( diff < 0.0 ) diff = -diff;
346 w = -1 + sqrt(2.0*exp(1.))*sqrt(x-turnpt);
347 if( diff == 0.0 )
return;
359 while( relerr > mach_eps && i<maxit){
363 s = 6.*(w+1.0)*(w+1.0);
364 w = w * ( 1.0 + r + r2/(2.0*( w+1.0)) - (2. * w -1.0)*r3/s );
365 if( w * x < 0.0 ) w = -w;
374 if(relerr < 0.0 ) relerr = -relerr;
377 if( i == maxit ) ierr = 2;
393 Real arg1 = (Vsrc + Is*Rs)/Vth_;
394 Real evd = exp(arg1);
395 Real lambWArg = Is*Rs*evd/
Vth_;
399 lambertw(lambWArg, lambWReturn, ierr, lambWError);
400 if(ierr == 1){std::cout <<
"LambertW error: argument is not in the domain" << std::endl;
return -1.0;}
401 if(ierr == 2){std::cout <<
"LambertW error: BUG!" << std::endl;}
402 Real Id = -Is+Vth_*(lambWReturn)/Rs;
419 for(uint i=0;i<n;i++){
427 for(uint i=0;i<n;i++){
428 (*Ip)[i] =
Newton(I0,(*Vsrc_)[i],(*Sp)[0],(*Sp)[1]);
442 using Teuchos::RCP;
using Teuchos::rcp;
444 uint n = Imeas_->size();
445 STDV I( rcp(
new vector(n,0.0) ) );
452 for(uint i=0;i<n;i++){
453 val += ((*Ip)[i]-(*Imeas_)[i])*((*Ip)[i]-(*Imeas_)[i]);
473 for(uint i=0;i<n;i++){
474 (*lambdap)[i] = ((*Imeas_)[i]-(*Ip)[i])/
diodeI((*Ip)[i],(*Vsrc_)[i],(*Sp)[0],(*Sp)[1]);
493 for(uint i=0;i<n;i++){
494 (*sensp)[i] = -
diodeIs((*Ip)[i],(*Vsrc_)[i],(*Sp)[0],(*Sp)[1])/
diodeI((*Ip)[i],(*Vsrc_)[i],(*Sp)[0],(*Sp)[1]);
513 for(uint i=0;i<n;i++){
514 (*sensp)[i] = -
diodeRs((*Ip)[i],(*Vsrc_)[i],(*Sp)[0],(*Sp)[1])/
diodeI((*Ip)[i],(*Vsrc_)[i],(*Sp)[0],(*Sp)[1]);
521 using Teuchos::RCP;
using Teuchos::rcp;
525 uint n = Imeas_->size();
527 STDV I( rcp(
new vector(n,0.0) ) );
535 STDV lambda( rcp(
new vector(n,0.0) ) );
542 (*gp)[0] = 0.0; (*gp)[1] = 0.0;
543 for(uint i=0;i<n;i++){
544 (*gp)[0] +=
diodeIs((*Ip)[i],(*Vsrc_)[i],(*Sp)[0],(*Sp)[1])*(*lambdap)[i];
545 (*gp)[1] +=
diodeRs((*Ip)[i],(*Vsrc_)[i],(*Sp)[0],(*Sp)[1])*(*lambdap)[i];
550 STDV sensIs( rcp(
new vector(n,0.0) ) );
551 STDV sensRs( rcp(
new vector(n,0.0) ) );
560 std::ofstream output (
"Sensitivities.dat");
561 for(uint k=0;k<n;k++){
562 if(output.is_open()){
563 output << std::scientific << (*sensIsp)[k] <<
" " << (*sensRsp)[k] <<
"\n";
568 (*gp)[0] = 0.0; (*gp)[1] = 0.0;
569 for(uint i=0;i<n;i++){
570 (*gp)[0] += ((*Ip)[i]-(*Imeas_)[i])*(*sensIsp)[i];
571 (*gp)[1] += ((*Ip)[i]-(*Imeas_)[i])*(*sensRsp)[i];
587 using Teuchos::RCP;
using Teuchos::rcp;
592 else if(use_hessvec_==1){
597 uint n = Imeas_->size();
599 STDV I( rcp(
new vector(n,0.0) ) );
605 STDV lambda( rcp(
new vector(n,0.0) ) );
611 STDV w( rcp(
new vector(n,0.0) ) );
615 for(uint i=0;i<n;i++){
616 (*wp)[i] = ( (*vp)[0] *
diodeIs( (*Ip)[i],(*Vsrc_)[i],(*Sp)[0],(*Sp)[1] ) + (*vp)[1] *
diodeRs( (*Ip)[i],(*Vsrc_)[i],(*Sp)[0],(*Sp)[1] ) ) /
diodeI((*Ip)[i],(*Vsrc_)[i],(*Sp)[0],(*Sp)[1]);
619 STDV p( rcp(
new vector(n,0.0) ) );
623 for(uint j=0;j<n;j++){
624 (*pp)[j] = ( (*wp)[j] + (*lambdap)[j] *
diodeII( (*Ip)[j],(*Vsrc_)[j],(*Sp)[0],(*Sp)[1] ) * (*wp)[j] - (*lambdap)[j] *
diodeIIs( (*Ip)[j],(*Vsrc_)[j],(*Sp)[0],(*Sp)[1] ) * (*vp)[0] - (*lambdap)[j] *
diodeIRs( (*Ip)[j],(*Vsrc_)[j],(*Sp)[0],(*Sp)[1] ) * (*vp)[1] ) /
diodeI( (*Ip)[j],(*Vsrc_)[j],(*Sp)[0],(*Sp)[1] );
628 (*hvp)[0] = 0.0;(*hvp)[1] = 0.0;
629 for(uint k=0;k<n;k++){
630 (*hvp)[0] +=
diodeIs( (*Ip)[k],(*Vsrc_)[k],(*Sp)[0],(*Sp)[1] ) * (*pp)[k] - (*lambdap)[k] * (*wp)[k] *
diodeIIs( (*Ip)[k],(*Vsrc_)[k],(*Sp)[0],(*Sp)[1] ) + (*lambdap)[k] * (*vp)[0] *
diodeIsIs( (*Ip)[k],(*Vsrc_)[k],(*Sp)[0],(*Sp)[1] ) + (*lambdap)[k] * (*vp)[1] *
diodeIsRs( (*Ip)[k],(*Vsrc_)[k],(*Sp)[0],(*Sp)[1] );
631 (*hvp)[1] +=
diodeRs( (*Ip)[k],(*Vsrc_)[k],(*Sp)[0],(*Sp)[1] ) * (*pp)[k] - (*lambdap)[k] * (*wp)[k] *
diodeIRs( (*Ip)[k],(*Vsrc_)[k],(*Sp)[0],(*Sp)[1] ) + (*lambdap)[k] * (*vp)[0] *
diodeIsRs( (*Ip)[k],(*Vsrc_)[k],(*Sp)[0],(*Sp)[1] ) + (*lambdap)[k] * (*vp)[1] *
diodeRsRs( (*Ip)[k],(*Vsrc_)[k],(*Sp)[0],(*Sp)[1] );
634 else if(use_hessvec_==2){
640 uint n = Imeas_->size();
642 STDV I( rcp(
new vector(n,0.0) ) );
649 STDV sensIs( rcp(
new vector(n,0.0) ) );
650 STDV sensRs( rcp(
new vector(n,0.0) ) );
659 Real H11 = 0.0; Real H12 = 0.0; Real H22 = 0.0;
660 for(uint k=0;k<n;k++){
661 H11 += (*sensIsp)[k]*(*sensIsp)[k];
662 H12 += (*sensIsp)[k]*(*sensRsp)[k];
663 H22 += (*sensRsp)[k]*(*sensRsp)[k];
667 (*hvp)[0] = H11*(*vp)[0] + H12*(*vp)[1];
668 (*hvp)[1] = H12*(*vp)[0] + H22*(*vp)[1];
686 void generate_plot(Real Is_lo, Real Is_up, Real Is_step, Real Rs_lo, Real Rs_up, Real Rs_step){
687 Teuchos::RCP<std::vector<double> > S_rcp = Teuchos::rcp(
new std::vector<double>(2,0.0) );
689 std::ofstream output (
"Objective.dat");
695 int n = (Is_up-Is_lo)/Is_step + 1;
696 int m = (Rs_up-Rs_lo)/Rs_step + 1;
697 for(
int i=0;i<n;i++){
698 Is = Is_lo + i*Is_step;
699 for(
int j=0;j<m;j++){
700 Rs = Rs_lo + j*Rs_step;
704 if(output.is_open()){
705 output << std::scientific << Is <<
" " << Rs <<
" " << val <<
"\n";
Provides the interface to evaluate objective functions.
bool use_adjoint_
If true, use adjoint gradient computation, else compute gradient using sensitivities.
Real diodeIsRs(const Real I, const Real Vsrc, const Real Is, const Real Rs)
Second derivative of diode equation wrt Is and Rs.
Real noise_
Percentage of noise to add to measurements; if 0.0 - no noise.
Real diodeIsIs(const Real I, const Real Vsrc, const Real Is, const Real Rs)
Second derivative of diode equation wrt Is^2.
std::vector< Real > vector
Objective_DiodeCircuit(Real Vth, std::ifstream &input_file, bool lambertw, Real noise, bool use_adjoint, int use_hessvec)
A constructor using data from given file.
Real lambertWCurrent(Real Is, Real Rs, Real Vsrc)
Find currents using Lambert-W function.
int use_hessvec_
0 - use FD(with scaling), 1 - use exact implementation (with second order derivatives), 2 - use Gauss-Newton approximation (first order derivatives only)
Provides the std::vector implementation of the ROL::Vector interface that handles scalings in the inn...
Teuchos::RCP< vector > getVector(V &x)
virtual void hessVec(Vector< Real > &hv, const Vector< Real > &v, const Vector< Real > &x, Real &tol)
Apply Hessian approximation to vector.
void solve_sensitivity_Is(Vector< Real > &sens, const Vector< Real > &I, const Vector< Real > &S)
Solve the sensitivity equation wrt Is.
void solve_adjoint(Vector< Real > &lambda, const Vector< Real > &I, const Vector< Real > &S)
Solve the adjoint equation.
void gradient(Vector< Real > &g, const Vector< Real > &S, Real &tol)
Compute the gradient of the reduced objective function either using adjoint or using sensitivities...
Teuchos::RCP< std::vector< Real > > Imeas_
Vector of measured currents in DC analysis (data)
Real Vth_
Thermal voltage (constant)
void generate_plot(Real Is_lo, Real Is_up, Real Is_step, Real Rs_lo, Real Rs_up, Real Rs_step)
Generate data to plot objective function.
Defines the linear algebra or vector space interface.
Teuchos::RCP< std::vector< Real > > Vsrc_
Vector of source voltages in DC analysis (input)
The diode circuit problem.
Real value(const Vector< Real > &S, Real &tol)
Evaluate objective function.
Real diodeI(const Real I, const Real Vsrc, const Real Is, const Real Rs)
Derivative of diode equation wrt I.
Provides the std::vector implementation of the ROL::Vector interface.
void lambertw(Real x, Real &w, int &ierr, Real &xi)
Lambert-W function for diodes.
Real Newton(const Real I, const Real Vsrc, const Real Is, const Real Rs)
Newton's method with line search.
void hessVec(Vector< Real > &hv, const Vector< Real > &v, const Vector< Real > &S, Real &tol)
Compute the Hessian-vector product of the reduced objective function.
void solve_circuit(Vector< Real > &I, const Vector< Real > &S)
Solve circuit given optimization parameters Is and Rs.
Provides the std::vector implementation of the ROL::Vector interface that handles scalings in the inn...
PrimalScaledStdVector< Real > PSV
bool lambertw_
If true, use Lambert-W function to solve circuit, else use Newton's method.
Real diode(const Real I, const Real Vsrc, const Real Is, const Real Rs)
Diode equation.
Real diodeIs(const Real I, const Real Vsrc, const Real Is, const Real Rs)
Derivative of diode equation wrt Is.
Real diodeRsRs(const Real I, const Real Vsrc, const Real Is, const Real Rs)
Second derivative of diode equation wrt Rs^2.
Objective_DiodeCircuit(Real Vth, Real Vsrc_min, Real Vsrc_max, Real Vsrc_step, Real true_Is, Real true_Rs, bool lambertw, Real noise, bool use_adjoint, int use_hessvec)
A constructor generating data.
void solve_sensitivity_Rs(Vector< Real > &sens, const Vector< Real > &I, const Vector< Real > &S)
Solve the sensitivity equation wrt Rs.
Real diodeIIs(const Real I, const Real Vsrc, const Real Is, const Real Rs)
Second derivative of diode equation wrt I and Is.
Real diodeIRs(const Real I, const Real Vsrc, const Real Is, const Real Rs)
Second derivative of diode equation wrt I and Rs.
Real diodeII(const Real I, const Real Vsrc, const Real Is, const Real Rs)
Second derivative of diode equation wrt I^2.
Teuchos::RCP< const vector > getVector(const V &x)
DualScaledStdVector< Real > DSV
Real diodeRs(const Real I, const Real Vsrc, const Real Is, const Real Rs)
Derivative of diode equation wrt Rs.
void set_method(bool lambertw)
Change the method for solving the circuit if needed.