Skip to content

Commit d7cd7d3

Browse files
Keep sub-evaluators up to date after integration step
Evaluators which contain "children" evaluators such as systems should be given the chance to keep their sub-evaluators up to date after events like an integrator step. With the `update()` method, an external source can notify the evaluator when its state has been updated so that it can then go and update its children. This is useful for callbacks, since callbacks will probably want to query individual components rather than systems.
1 parent 0e07a26 commit d7cd7d3

File tree

4 files changed

+96
-149
lines changed

4 files changed

+96
-149
lines changed

examples/PhasorDynamics/Example1/example1.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,10 @@ int main()
9595
// push it into output, which is updated outside the callback.
9696
auto output_cb = [&](double t)
9797
{
98-
std::vector<double>& yval = sys.y();
99-
10098
output.push_back({.ti = t,
101-
.Vr = yval[0],
102-
.Vi = yval[1],
103-
.dw = yval[3]});
99+
.Vr = bus1.Vr(),
100+
.Vi = bus1.Vi(),
101+
.dw = gen.y()[1]});
104102
};
105103

106104
// The above lambda is equivalent to writing

src/Model/Evaluator.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ namespace GridKit
5656
virtual void setTolerances(real_type& rtol, real_type& atol) const = 0;
5757
virtual void setMaxSteps(IdxT& msa) const = 0;
5858

59+
/// @brief Let the `Evaluator` know that its state has been updated externally (for example by an integrator),
60+
/// in case it needs to keep other things up to date based on its internal state.
61+
virtual void update()
62+
{
63+
}
64+
5965
virtual std::vector<ScalarT>& y() = 0;
6066
virtual const std::vector<ScalarT>& y() const = 0;
6167

src/Model/PhasorDynamics/SystemModel.hpp

Lines changed: 85 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -343,42 +343,15 @@ namespace GridKit
343343
*/
344344
int evaluateIntegrand()
345345
{
346-
// Update variables
347-
IdxT varOffset = 0;
348-
IdxT optOffset = 0;
346+
updateChildren();
347+
349348
for (const auto& bus : buses_)
350349
{
351-
for (IdxT j = 0; j < bus->size(); ++j)
352-
{
353-
bus->y()[j] = y_[varOffset + j];
354-
bus->yp()[j] = yp_[varOffset + j];
355-
}
356-
varOffset += bus->size();
357-
358-
for (IdxT j = 0; j < bus->sizeParams(); ++j)
359-
{
360-
bus->param()[j] = param_[optOffset + j];
361-
}
362-
optOffset += bus->sizeParams();
363-
364350
bus->evaluateIntegrand();
365351
}
366352

367353
for (const auto& component : components_)
368354
{
369-
for (IdxT j = 0; j < component->size(); ++j)
370-
{
371-
component->y()[j] = y_[varOffset + j];
372-
component->yp()[j] = yp_[varOffset + j];
373-
}
374-
varOffset += component->size();
375-
376-
for (IdxT j = 0; j < component->sizeParams(); ++j)
377-
{
378-
component->param()[j] = param_[optOffset + j];
379-
}
380-
optOffset += component->sizeParams();
381-
382355
component->evaluateIntegrand();
383356
}
384357

@@ -413,45 +386,9 @@ namespace GridKit
413386
*/
414387
int initializeAdjoint()
415388
{
416-
IdxT offset = 0;
417-
IdxT optOffset = 0;
418-
419-
// Update bus variables and optimization parameters
420-
for (const auto& bus : buses_)
421-
{
422-
for (IdxT j = 0; j < bus->size(); ++j)
423-
{
424-
bus->y()[j] = y_[offset + j];
425-
bus->yp()[j] = yp_[offset + j];
426-
}
427-
offset += bus->size();
389+
updateChildren();
428390

429-
for (IdxT j = 0; j < bus->sizeParams(); ++j)
430-
{
431-
bus->param()[j] = param_[optOffset + j];
432-
}
433-
optOffset += bus->sizeParams();
434-
}
435-
436-
// Update component variables and optimization parameters
437-
for (const auto& component : components_)
438-
{
439-
for (IdxT j = 0; j < component->size(); ++j)
440-
{
441-
component->y()[j] = y_[offset + j];
442-
component->yp()[j] = yp_[offset + j];
443-
}
444-
offset += component->size();
445-
446-
for (IdxT j = 0; j < component->sizeParams(); ++j)
447-
{
448-
component->param()[j] = param_[optOffset + j];
449-
}
450-
optOffset += component->sizeParams();
451-
}
452-
453-
// Reset counter
454-
offset = 0;
391+
size_t offset = 0;
455392

456393
// Initialize bus adjoints
457394
for (const auto& bus : buses_)
@@ -491,45 +428,7 @@ namespace GridKit
491428
*/
492429
int evaluateAdjointResidual()
493430
{
494-
IdxT varOffset = 0;
495-
IdxT optOffset = 0;
496-
497-
// Update variables in component models
498-
for (const auto& bus : buses_)
499-
{
500-
for (IdxT j = 0; j < bus->size(); ++j)
501-
{
502-
bus->y()[j] = y_[varOffset + j];
503-
bus->yp()[j] = yp_[varOffset + j];
504-
bus->yB()[j] = yB_[varOffset + j];
505-
bus->ypB()[j] = ypB_[varOffset + j];
506-
}
507-
varOffset += bus->size();
508-
509-
for (IdxT j = 0; j < bus->sizeParams(); ++j)
510-
{
511-
bus->param()[j] = param_[optOffset + j];
512-
}
513-
optOffset += bus->sizeParams();
514-
}
515-
516-
for (const auto& component : components_)
517-
{
518-
for (IdxT j = 0; j < component->size(); ++j)
519-
{
520-
component->y()[j] = y_[varOffset + j];
521-
component->yp()[j] = yp_[varOffset + j];
522-
component->yB()[j] = yB_[varOffset + j];
523-
component->ypB()[j] = ypB_[varOffset + j];
524-
}
525-
varOffset += component->size();
526-
527-
for (IdxT j = 0; j < component->sizeParams(); ++j)
528-
{
529-
component->param()[j] = param_[optOffset + j];
530-
}
531-
optOffset += component->sizeParams();
532-
}
431+
updateChildrenAdjoint();
533432

534433
for (const auto& bus : buses_)
535434
{
@@ -575,44 +474,7 @@ namespace GridKit
575474
*/
576475
int evaluateAdjointIntegrand()
577476
{
578-
// First, update variables
579-
IdxT varOffset = 0;
580-
IdxT optOffset = 0;
581-
for (const auto& bus : buses_)
582-
{
583-
for (IdxT j = 0; j < bus->size(); ++j)
584-
{
585-
bus->y()[j] = y_[varOffset + j];
586-
bus->yp()[j] = yp_[varOffset + j];
587-
bus->yB()[j] = yB_[varOffset + j];
588-
bus->ypB()[j] = ypB_[varOffset + j];
589-
}
590-
varOffset += bus->size();
591-
592-
for (IdxT j = 0; j < bus->sizeParams(); ++j)
593-
{
594-
bus->param()[j] = param_[optOffset + j];
595-
}
596-
optOffset += bus->sizeParams();
597-
}
598-
599-
for (const auto& component : components_)
600-
{
601-
for (IdxT j = 0; j < component->size(); ++j)
602-
{
603-
component->y()[j] = y_[varOffset + j];
604-
component->yp()[j] = yp_[varOffset + j];
605-
component->yB()[j] = yB_[varOffset + j];
606-
component->ypB()[j] = ypB_[varOffset + j];
607-
}
608-
varOffset += component->size();
609-
610-
for (IdxT j = 0; j < component->sizeParams(); ++j)
611-
{
612-
component->param()[j] = param_[optOffset + j];
613-
}
614-
optOffset += component->sizeParams();
615-
}
477+
updateChildrenAdjoint();
616478

617479
// Evaluate integrand and update global vector
618480
for (const auto& component : components_)
@@ -648,10 +510,89 @@ namespace GridKit
648510
components_.push_back(component);
649511
}
650512

513+
void update() override
514+
{
515+
updateChildrenAdjoint();
516+
}
517+
651518
private:
652519
std::vector<bus_type*> buses_;
653520
std::vector<component_type*> components_;
654521

522+
/// @brief Whenever the internal state of a system is updated, the system
523+
/// needs to reflect those changes in its "children" aka buses and
524+
/// components. `updateChildren` will only update `y`, `yp`, and
525+
/// `param` - call when you know only the internal state of those
526+
/// variables has been updated.
527+
void updateChildren()
528+
{
529+
// Update variables
530+
IdxT varOffset = 0;
531+
IdxT optOffset = 0;
532+
for (const auto& bus : buses_)
533+
{
534+
for (IdxT j = 0; j < bus->size(); ++j)
535+
{
536+
bus->y()[j] = y_[varOffset + j];
537+
bus->yp()[j] = yp_[varOffset + j];
538+
}
539+
varOffset += bus->size();
540+
541+
for (IdxT j = 0; j < bus->sizeParams(); ++j)
542+
{
543+
bus->param()[j] = param_[optOffset + j];
544+
}
545+
optOffset += bus->sizeParams();
546+
}
547+
548+
for (const auto& component : components_)
549+
{
550+
for (IdxT j = 0; j < component->size(); ++j)
551+
{
552+
component->y()[j] = y_[varOffset + j];
553+
component->yp()[j] = yp_[varOffset + j];
554+
}
555+
varOffset += component->size();
556+
557+
for (IdxT j = 0; j < component->sizeParams(); ++j)
558+
{
559+
component->param()[j] = param_[optOffset + j];
560+
}
561+
optOffset += component->sizeParams();
562+
}
563+
}
564+
565+
/// @brief Whenever the internal state of a system is updated, the system
566+
/// needs to reflect those changes in its "children" aka buses and
567+
/// components. `updateChildrenAdjoint` will update all internal
568+
/// variables of this system's children, including adjoint variables.
569+
void updateChildrenAdjoint()
570+
{
571+
// Update all non-adjoint state
572+
updateChildren();
573+
574+
IdxT varOffset = 0;
575+
IdxT optOffset = 0;
576+
for (const auto& bus : buses_)
577+
{
578+
for (IdxT j = 0; j < bus->size(); ++j)
579+
{
580+
bus->yB()[j] = yB_[varOffset + j];
581+
bus->ypB()[j] = ypB_[varOffset + j];
582+
}
583+
varOffset += bus->size();
584+
}
585+
586+
for (const auto& component : components_)
587+
{
588+
for (IdxT j = 0; j < component->size(); ++j)
589+
{
590+
component->yB()[j] = yB_[varOffset + j];
591+
component->ypB()[j] = ypB_[varOffset + j];
592+
}
593+
varOffset += component->size();
594+
}
595+
}
655596
}; // class SystemModel
656597

657598
} // namespace PhasorDynamics

src/Solver/Dynamic/Ida.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ namespace AnalysisManager
231231
model_->updateTime(tret, 0.0);
232232
copyVec(yy_, model_->y());
233233
copyVec(yp_, model_->yp());
234+
model_->update();
234235

235236
(*step_callback)(tret);
236237
}
@@ -246,6 +247,7 @@ namespace AnalysisManager
246247
model_->updateTime(tf, 0.0);
247248
copyVec(yy_, model_->y());
248249
copyVec(yp_, model_->yp());
250+
model_->update();
249251

250252
// std::cout << "\n";
251253
return retval;

0 commit comments

Comments
 (0)