Power System Platform  2026w23a-beta
Loading...
Searching...
No Matches
EMTElement Class Reference

Element to connect ATP-EMTP. More...

#include <EMTElement.h>

Inheritance diagram for EMTElement:
Collaboration diagram for EMTElement:

Public Member Functions

 EMTElement (wxString name)
 
virtual ElementGetCopy ()
 Get a the element copy.
 
virtual bool AddParent (Element *parent, wxPoint2DDouble position)
 Add a parent to the element. This method must be used on power elements that connect to a bus, so the parent must be a bus. The element basic points are calculated in this method, so apply this when the element is being inserted.
 
virtual void DrawDC (GUIColour *guiColour, wxPoint2DDouble translation, double scale, wxGraphicsContext *gc) const
 Draw the element using GDI+.
 
virtual void DrawDC (GUIColour *guiColour, wxPoint2DDouble translation, double scale, wxDC &dc) const
 Draw the element using wxDC.
 
virtual bool Contains (wxPoint2DDouble position) const
 Checks if the element contains a position.
 
virtual bool Intersects (wxRect2DDouble rect) const
 Check if the element's rect intersects other rect.
 
virtual void Rotate (bool clockwise=true)
 Rotate the element.
 
virtual bool GetContextMenu (wxMenu &menu)
 Get the element contex menu.
 
virtual wxString GetTipText () const
 Get the tip text.
 
virtual bool ShowForm (wxWindow *parent, Element *element, wxWindow *workspace=nullptr)
 Show element data form.
 
virtual rapidxml::xml_node * SaveElement (rapidxml::xml_document<> &doc, rapidxml::xml_node<> *elementListNode)
 
virtual bool OpenElement (rapidxml::xml_node<> *elementNode, std::vector< Element * > parentList)
 
virtual EMTElementData GetEMTElementData ()
 
virtual void SetEMTElementData (EMTElementData data)
 
wxArrayString GetATPNodes (wxArrayString atpFile)
 
bool SetATPParameter (wxTextFile &atpFile, const wxString &card, const int &line, const int &initPos, const int &size, const wxString &value)
 
bool AddConnectionToNode (wxTextFile &atpFile, const wxString &node)
 
void MedianFilter (std::vector< double > &data)
 
bool CalculateCurrent (wxString &errorMsg, const Mode &mode=Mode::Phasor, const bool &saveRawData=false, const bool &saveFFTData=false)
 
void UpdateData (const PropertiesData *properties=nullptr, bool updateVoltageBase=false)
 
void SetNominalVoltage (std::vector< double > nominalVoltage, std::vector< ElectricalUnit > nominalVoltageUnit)
 Set nominal voltage of the element.
 
- Public Member Functions inherited from Shunt
virtual void Move (wxPoint2DDouble position)
 Move the element other position.
 
virtual void MoveNode (Element *element, wxPoint2DDouble position)
 Move a node. StartMove(wxPoint2DDouble position) before start moving.
 
virtual void StartMove (wxPoint2DDouble position)
 Update the element attributes related to the movement.
 
virtual void RotateNode (Element *parent, bool clockwise=true)
 Rotate a node.
 
virtual void RemoveParent (Element *parent)
 Remove a parent.
 
virtual bool NodeContains (wxPoint2DDouble position)
 Check if a node contains a point. If contains, set the attributes related to node movement.
 
virtual bool SetNodeParent (Element *parent)
 Set a perent to the node. If all conditions are met, a new parent are added to the element and the points related to the nodes will be calculated.
 
virtual void UpdateNodes ()
 Update the nodes according to the parents. If a parent is removed, use this method.
 
- Public Member Functions inherited from PowerElement
 PowerElement ()
 Constructor.
 
virtual ~PowerElement ()
 Destructor.
 
virtual wxPoint2DDouble GetSwitchPoint (Element *parent, wxPoint2DDouble parentPoint, wxPoint2DDouble secondPoint) const
 Get the correct switch position.
 
virtual bool SwitchesContains (wxPoint2DDouble position) const
 Check if switch contains position.
 
virtual void UpdateSwitches ()
 Update the switch position.
 
virtual void DrawDCSwitches (GUIColour *guiColour, wxGraphicsContext *gc) const
 Draw switch.
 
virtual void DrawDCSwitches (GUIColour *guiColour, wxDC &dc) const
 
virtual void CalculatePowerFlowPts (std::vector< wxPoint2DDouble > edges)
 Calculate the points of the power flow arrows.
 
virtual void DrawDCPowerFlowPts (GUIColour *guiColour, wxGraphicsContext *gc) const
 Draw power flow arrows.
 
virtual void DrawDCPowerFlowPts (GUIColour *guiColour, wxDC &dc) const
 
virtual void SetSwitchingData (SwitchingData data)
 Set the switching data of the element.
 
virtual SwitchingData GetSwitchingData ()
 Returns the switching data of the element.
 
virtual void SetPowerFlowDirection (PowerFlowDirection pfDirection)
 Set the direction of the power flow.
 
virtual PowerFlowDirection GetPowerFlowDirection () const
 Return the direction of the power flow.
 
virtual bool GetPlotData (ElementPlotData &plotData, PlotStudy study=PlotStudy::STABILITY)
 Fill the plot data.
 
virtual bool HaveDynamicEvent () const
 Check if the power element have dynamic event.
 
virtual void SetDynamicEvent (bool dynEvent=true)
 Set if the power element have dynamic event.
 
virtual double GetValueFromUnit (double value, ElectricalUnit valueUnit) const
 
virtual void SaveCADProperties (rapidxml::xml_document<> &doc, rapidxml::xml_node<> *elementNode)
 
virtual void SaveSwitchingData (rapidxml::xml_document<> &doc, rapidxml::xml_node<> *electricalNode)
 
virtual bool OpenCADProperties (rapidxml::xml_node<> *elementNode, std::vector< Element * > parentList)
 
virtual bool OpenSwitchingData (rapidxml::xml_node<> *electricalNode)
 
- Public Member Functions inherited from Element
 Element ()
 Constructor.
 
virtual ~Element ()
 Destructor.
 
void SetDragging (bool dragging=true)
 Set if the element are being dragged.
 
void SetHeight (double height)
 Set element height.
 
void SetPosition (const wxPoint2DDouble position)
 Set the element position and update the rectangle.
 
void SetSelected (bool selected=true)
 Set element selection.
 
void SetWidth (double width)
 Set element width.
 
void SetAngle (double angle)
 Set element angle.
 
void ShowPickbox (bool showPickbox=true)
 Set if the pickbox is shown.
 
void SetBorderSize (double borderSize)
 Set the size of the border (shown in selected elements).
 
bool SetOnline (bool online=true)
 Set if the element is online or offline.
 
virtual void SetPointList (std::vector< wxPoint2DDouble > pointList)
 Set the list of points that connect the element to the bus.
 
ElementType GetElementType ()
 
wxRect2DDouble GetRect () const
 Get the element rectangle.
 
wxPoint2DDouble GetPosition () const
 Get the element position.
 
bool IsDragging () const
 Checks if the element is being dragged.
 
double GetHeight () const
 Get the element height.
 
bool IsSelected () const
 Checks if the element is selected.
 
double GetWidth () const
 Get the element width.
 
double GetAngle () const
 Get the element angle.
 
double GetRotationAngle () const
 Get the angle of rotation.
 
bool IsPickboxShown () const
 Checks if the pickbox is shown.
 
bool IsOnline () const
 Checks if the element is online or offline.
 
virtual std::vector< wxPoint2DDouble > GetPointList () const
 Get the list of points that connect the element to bus.
 
virtual void AddParent (Element *parent)
 Add a parent to the element.
 
virtual void SetID (int id)
 Set the element ID.
 
virtual int GetID () const
 Get the element ID.
 
virtual void AddChild (Element *child)
 Add a child to the child list.
 
virtual void RemoveChild (Element *child)
 Remove a child from the list.
 
virtual void ReplaceChild (Element *oldChild, Element *newChild)
 Replace a child from the list.
 
virtual void AddPoint (wxPoint2DDouble point)
 Add point to the list of points that connect the element to the bus.
 
void SetParent (Element *parent, int num)
 
void SetChild (Element *child, int num)
 
virtual void ReplaceParent (Element *oldParent, Element *newParent)
 Replace a parent.
 
virtual bool PickboxContains (wxPoint2DDouble position)
 Check if a pickbox contains a point. If contains the attributes related to pickbox movement will be calculated.
 
virtual void MovePickbox (wxPoint2DDouble position)
 Move the pickbox.
 
virtual wxCursor GetBestPickboxCursor () const
 Get the best cursor to shown to the user when the mouse is above a pickbox.
 
virtual void ResetPickboxes ()
 Remove the pickboxes.
 
virtual void ResetNodes ()
 Remove the active nodes.
 
virtual wxPoint2DDouble WorldToScreen (wxPoint2DDouble translation, double scale, double offsetX=0.0, double offsetY=0.0) const
 Convert the element position to screen position.
 
virtual wxPoint2DDouble WorldToScreen (wxPoint2DDouble position, wxPoint2DDouble translation, double scale, double offsetX=0.0, double offsetY=0.0) const
 Convert a generic position to screen position.
 
virtual bool RotatedRectanglesIntersects (wxRect2DDouble rect1, wxRect2DDouble rect2, double angle1, double angle2) const
 Check if two roteted rectangles intersect.
 
virtual void DrawDCRectangle (wxPoint2DDouble position, double width, double height, double angle, wxDC &dc) const
 Draw a circle.
 
virtual void DrawDCRoundedRectRotated (wxDC &dc, const wxPoint2DDouble &center, double width, double height, double radius, double angleDeg, int arcSegments=8) const
 
virtual void DrawDCCircle (wxPoint2DDouble position, double radius, int numSegments, wxGraphicsContext *gc) const
 Draw a circle using device context.
 
virtual void DrawDCCircle (wxPoint2DDouble position, double radius, wxDC &dc) const
 
virtual void DrawDCArc (wxPoint2DDouble position, double radius, double initAngle, double finalAngle, int numSegments, wxGraphicsContext *gc) const
 
virtual void DrawDCArc (wxPoint2DDouble position, double radius, double initAngle, double finalAngle, wxDC &dc) const
 
virtual void DrawDCTriangle (std::vector< wxPoint2DDouble > points, wxGraphicsContext *gc) const
 Draw rectangle.
 
virtual void DrawDCTriangle (std::vector< wxPoint > points, wxDC &dc) const
 
virtual void DrawDCPickbox (wxPoint2DDouble position, wxGraphicsContext *gc) const
 Draw a point.
 
virtual wxPoint2DDouble RotateAtPosition (wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
 Rotate a point as element position being the origin.
 
virtual wxPoint2DDouble RotateLocal (wxPoint2DDouble local, double angleDeg) const
 
virtual wxPoint RotateAround (const wxPoint2DDouble &p, const wxPoint2DDouble &center, double angleDeg) const
 
virtual std::vector< Element * > GetParentList () const
 Get the parent list.
 
virtual std::vector< Element * > GetChildList () const
 Get the Child list.
 
virtual void CalculateBoundaries (wxPoint2DDouble &leftUp, wxPoint2DDouble &rightBottom) const
 Calculate the element boundaries.
 
virtual void GeneralMenuItens (wxMenu &menu)
 Insert general itens to context menu.
 
virtual double PointToLineDistance (wxPoint2DDouble point, int *segmentNumber=nullptr) const
 Calculate the distance between a line (formed by point list) and a point.
 
bool IsInserted () const
 Check if the element is properly inserted in the workspace.
 
void SetInserted (bool inserted=true)
 Set if the element is properly inserted in the workspace.
 
virtual bool OpenElement (rapidxml::xml_node<> *elementNode)
 
void SaveCADProperties (rapidxml::xml_document<> &doc, rapidxml::xml_node<> *elementNode)
 
bool OpenCADProperties (rapidxml::xml_node<> *elementNode)
 

Protected Member Functions

void DoMedianFilter (double *extension, std::vector< double > &result, const int &n)
 
wxString ATPField (double value, size_t width)
 
bool CheckLISFile (wxFileName fileName, wxString &errorMsg) const
 
- Protected Member Functions inherited from Shunt
void UpdateSwitchesPosition ()
 
void UpdatePowerFlowArrowsPosition ()
 
void DrawDCGround (wxPoint2DDouble position, wxGraphicsContext *gc) const
 
void DrawDCGround (wxPoint2DDouble position, wxDC &dc) const
 

Protected Attributes

EMTElementData m_data
 
- Protected Attributes inherited from PowerElement
SwitchingData m_swData
 
std::vector< std::vector< wxPoint2DDouble > > m_powerFlowArrow
 
PowerFlowDirection m_pfDirection = PowerFlowDirection::PF_NONE
 
wxColour m_busColour
 
wxColour m_onlineElementColour
 
wxColour m_offlineElementColour
 
wxColour m_closedSwitchColour
 
wxColour m_openedSwitchColour
 
wxColour m_powerFlowArrowColour
 
wxColour m_dynamicEventColour
 
bool m_dynEvent = false
 
- Protected Attributes inherited from Element
ElementType m_elementType = ElementType::TYPE_NONE
 
int m_elementID = 0
 
std::vector< Element * > m_parentList
 
std::vector< Element * > m_childList
 
wxRect2DDouble m_rect
 
wxPoint2DDouble m_position
 
double m_width = 0.0
 
double m_height = 0.0
 
double m_angle = 0.0
 
double m_borderSize = 2.0
 
double m_rotationAngle = 45.0
 
double m_switchSize = 10.0
 
std::vector< wxRect2DDouble > m_switchRect
 
bool m_selected = false
 
bool m_dragging = false
 
bool m_showPickbox = false
 
bool m_inserted = false
 
int m_activePickboxID = ID_PB_NONE
 
int m_activeNodeID = 0
 
std::vector< wxPoint2DDouble > m_pointList
 
std::vector< wxPoint2DDouble > m_movePts
 
wxPoint2DDouble m_moveStartPt
 
wxPoint2DDouble m_movePos
 
bool m_online = true
 

Additional Inherited Members

- Static Public Member Functions inherited from Element
static bool DoubleFromString (wxWindow *parent, wxString strValue, double &value, wxString errorMsg)
 Get a double value from a string. Show a error message if the conversion fail.
 
static bool IntFromString (wxWindow *parent, wxString strValue, int &value, wxString errorMsg)
 Convert a string to int. Show a error message if the conversion fail.
 
static wxString StringFromDouble (double value, int minDecimal=1, int maxDecimals=13)
 Convert a double value to string.
 

Detailed Description

Element to connect ATP-EMTP.

Author
Thales Lima Oliveira thale.nosp@m.s@uf.nosp@m.u.br
Date
01/07/2024

Definition at line 82 of file EMTElement.h.

Constructor & Destructor Documentation

◆ EMTElement() [1/2]

EMTElement::EMTElement ( )

Definition at line 21 of file EMTElement.cpp.

22{
23}

◆ EMTElement() [2/2]

EMTElement::EMTElement ( wxString  name)

Definition at line 25 of file EMTElement.cpp.

26{
27 m_data.name = name;
28}

◆ ~EMTElement()

EMTElement::~EMTElement ( )

Definition at line 30 of file EMTElement.cpp.

31{
32}

Member Function Documentation

◆ AddConnectionToNode()

bool EMTElement::AddConnectionToNode ( wxTextFile &  atpFile,
const wxString &  node 
)

Definition at line 434 of file EMTElement.cpp.

435{
436 // Get connnected bus data
437 bool hasBusData = false;
438 BusElectricalData busData;
439 if (!m_parentList.empty()) {
440 if (m_parentList[0] != nullptr) {
441 Bus* bus = static_cast<Bus*>(m_parentList[0]);
442 busData = bus->GetElectricalData();
443 hasBusData = true;
444 }
445 }
446
447 std::map<wxString, wxString> masks;
448
449 // Load masks from T94.atp file
450 wxTextFile t94File(Paths::GetDataPath() + "/atp/T94.atp");
451 if (t94File.Open()) {
452 wxString current;
453
454 for (size_t i = 0; i < t94File.GetLineCount(); i++) {
455 wxString line = t94File.GetLine(i);
456
457 if (line.StartsWith("[[") && line.EndsWith("]]")) {
458 current = line.Mid(2, line.Length() - 4);
459 masks[current].Clear();
460 continue;
461 }
462
463 if (!current.IsEmpty())
464 masks[current] += line + "\n";
465 }
466 }
467 t94File.Close();
468
469 for (const auto& [key, value] : masks) {
470 masks[key].RemoveLast(); // remove last newline character
471 }
472
473 // Load the FOREIGN MODELS from PSPMOD.mod file
474 wxTextFile pspmodFile(Paths::GetDataPath() + "/atp/PSPMOD.mod");
475 wxString pspmodString = "";
476 if (pspmodFile.Open()) {
477 pspmodString = pspmodFile.GetFirstLine();
478 while (!pspmodFile.Eof())
479 {
480 pspmodString += pspmodFile.GetNextLine() + "\n";
481 }
482 }
483 pspmodFile.Close();
484
485 masks["BRANCH"].Replace("T94L_", "PSPNC");
486 masks["BRANCH"].Replace("<STEP>", ATPField(m_data.pspStepSize, 6));
487
488 masks["SWITCH"].Replace("T94L_", "PSPNC");
489
490 //wxString switchMask = " PSPNC%c%s%c MEASURING %d";
491 //wxString sourceMask = "14PSPNC%c %s%s%s -1. 100.";
492
493 wxString lineStr = "";
494 int branchCardPos = -1, switchCardPos = -1, sourceCardPos = -1, modelsCardPos = -1, outputCardPos = -1;
495 int blankBranchCardPos = -1, blankModelsCardPos = -1;
496 lineStr = atpFile.GetFirstLine();
497 while (!atpFile.Eof())
498 {
499 if (lineStr.IsEmpty()) {
500 lineStr = atpFile.GetNextLine();
501 continue;
502 }
503 if (tolower(lineStr[0]) == 'c') {
504 lineStr = atpFile.GetNextLine();
505 continue; // Skip comments
506 }
507
508 if (lineStr.Find("/SWITCH") != wxNOT_FOUND) {
509 switchCardPos = atpFile.GetCurrentLine() + 1;
510 }
511 if (lineStr.Find("/SOURCE") != wxNOT_FOUND) {
512 sourceCardPos = atpFile.GetCurrentLine() + 1;
513 }
514 if (lineStr.Find("/BRANCH") != wxNOT_FOUND) {
515 branchCardPos = atpFile.GetCurrentLine() + 1;
516 }
517 if (lineStr.Find("/MODELS") != wxNOT_FOUND) {
518 modelsCardPos = atpFile.GetCurrentLine() + 1;
519 }
520 if (lineStr.Find("/OUTPUT") != wxNOT_FOUND) {
521 outputCardPos = atpFile.GetCurrentLine() + 1;
522 }
523 if (lineStr.Find("BLANK BRANCH") != wxNOT_FOUND) {
524 blankBranchCardPos = atpFile.GetCurrentLine() + 1;
525 }
526 if (lineStr.Find("BLANK MODELS") != wxNOT_FOUND) {
527 blankModelsCardPos = atpFile.GetCurrentLine() + 1;
528 }
529
530 lineStr = atpFile.GetNextLine();
531 }
532
533 if (branchCardPos < 0) return false;
534 if (outputCardPos < 0) return false;
535
536 if (modelsCardPos < 0 && branchCardPos > 0) {
537 // Models card must be the first card
538 atpFile.InsertLine("/MODELS", branchCardPos - 1);
539 atpFile.InsertLine("MODELS", branchCardPos);
540 atpFile.InsertLine("ENDMODELS", branchCardPos + 1);
541 modelsCardPos = branchCardPos - 1;
542 outputCardPos += 3;
543 blankBranchCardPos += 3;
544 if (blankModelsCardPos < 0)
545 {
546 atpFile.InsertLine("BLANK MODELS", blankBranchCardPos - 1);
547 blankModelsCardPos = blankBranchCardPos;
548 blankBranchCardPos++;
549
550 }
551 }
552
553 if (switchCardPos < 0 && outputCardPos > 0) {
554 atpFile.InsertLine("/SWITCH", outputCardPos - 1);
555 switchCardPos = outputCardPos;
556 outputCardPos++;
557 blankBranchCardPos++;
558 }
559
560 if (sourceCardPos < 0 && outputCardPos > 0) {
561 atpFile.InsertLine("/SOURCE", outputCardPos - 1);
562 sourceCardPos = outputCardPos;
563 outputCardPos++;
564 blankBranchCardPos++;
565 }
566
567 //for (char i = 'A'; i <= 'C'; ++i) {
568 // lineStr = wxString::Format(switchMask, i, node, i, i == 'A' ? 1 : 0);
569 // atpFile.InsertLine(lineStr, switchCardPos + (i - 'A'));
570 //}
571 //sourceCardPos += 3;
572
573 double voltage = std::abs(m_data.puVoltage) * m_data.baseVoltage * (std::sqrt(2) / std::sqrt(3)); // phase-ground, peak value
574 //wxString ampl = wxString::FromCDouble(voltage, 3); // Amplitude in pu
575 //wxString freq = wxString::FromCDouble(m_data.frequency, 5); // Frequency in Hz
576 // Insert spaces before to complete 10 characters
577 //while (freq.Length() < 10) freq = " " + freq;
578 //while (ampl.Length() < 10) ampl = " " + ampl;
579 for (char i = 'A'; i <= 'C'; ++i) {
580 wxString tag = wxString::Format("<AMP.%c >", i);
581 masks["SOURCE"].Replace(tag, ATPField(voltage, 10));
582
583 tag = wxString::Format("<FREQ.%c >", i);
584 masks["SOURCE"].Replace(tag, ATPField(m_data.frequency, 10));
585
586 double angle = std::arg(m_data.puVoltage) * 180.0 / M_PI - 120.0 * (i - 'A'); // Angle in degrees
587 tag = wxString::Format("<PHASE.%c >", i);
588 masks["SOURCE"].Replace(tag, ATPField(angle, 10));
589 }
590
591 lineStr = atpFile.GetFirstLine();
592 while (!atpFile.Eof())
593 {
594 if (lineStr.IsEmpty()) {
595 lineStr = atpFile.GetNextLine();
596 continue;
597 }
598 if (tolower(lineStr[0]) == 'c') {
599 lineStr = atpFile.GetNextLine();
600 continue; // Skip comments
601 }
602
603 if (lineStr.Find(node) != wxNOT_FOUND) {
604 lineStr.Replace(node, "PSPNC");
605 atpFile.RemoveLine(atpFile.GetCurrentLine());
606 atpFile.InsertLine(lineStr, atpFile.GetCurrentLine());
607 }
608
609 if (lineStr.Find("/MODELS") != wxNOT_FOUND)
610 atpFile.InsertLine(pspmodString, atpFile.GetCurrentLine() + 2);
611
612 if (lineStr.Find("/SWITCH") != wxNOT_FOUND)
613 atpFile.InsertLine(masks["SWITCH"], atpFile.GetCurrentLine() + 1);
614
615 if (lineStr.Find("/SOURCE") != wxNOT_FOUND)
616 atpFile.InsertLine(masks["SOURCE"], atpFile.GetCurrentLine() + 1);
617
618 if (lineStr.Find("/BRANCH") != wxNOT_FOUND)
619 atpFile.InsertLine(masks["BRANCH"], atpFile.GetCurrentLine() + 1);
620
621 lineStr = atpFile.GetNextLine();
622 }
623
624 lineStr = atpFile.GetFirstLine();
625 while (!atpFile.Eof())
626 {
627 lineStr += atpFile.GetNextLine() + "\n";
628
629 }
630
631
632 //int cardPos = sourceCardPos;
633 //for (char i = 'A'; i <= 'C'; ++i) {
634 // wxString angle = wxString::FromCDouble(std::arg(m_data.puVoltage) * 180.0 / M_PI - 120.0 * (i - 'A'), 5); // Angle in degrees
635 //
636 // // Insert spaces before to complete 10 characters
637 // while (angle.Length() < 10) angle = " " + angle;
638 //
639 // //lineStr = wxString::Format(sourceMask, i, ampl, freq, angle);
640 // atpFile.InsertLine(lineStr, cardPos);
641 // cardPos++;
642 //
643 // if (hasBusData) {
644 // // Insert harmonic voltage
645 // for (size_t j = 0; j < busData.harmonicOrder.size(); ++j) {
646 // int order = busData.harmonicOrder[j];
647 // if (order == 1) continue; // Skip fundamental
648 //
649 // std::complex<double> harmVoltage = busData.harmonicVoltage[j];
650 //
651 // voltage = std::abs(busData.harmonicVoltage[j]) * m_data.baseVoltage * (std::sqrt(2) / std::sqrt(3));
652 // wxString amplH = wxString::FromCDouble(voltage, 3);
653 // while (amplH.Length() < 10) amplH = " " + amplH;
654 //
655 // wxString freqH = wxString::FromCDouble(m_data.frequency * static_cast<double>(order), 5);
656 // while (freqH.Length() < 10) freqH = " " + freqH;
657 //
658 // double angleValue = std::arg(harmVoltage) * 180.0 / M_PI;
659 // if (order % 3 == 1) { // Positive sequence
660 // angleValue += -120.0 * (i - 'A');
661 // }
662 // else if (order % 3 == 2) { // Negative sequence
663 // angleValue += 120.0 * (i - 'A');
664 // }
665 // // Zero sequence doesn't change the angle because it's the same for all phases
666 //
667 // wxString angleH = wxString::FromCDouble(angleValue, 5);
668 // while (angleH.Length() < 10) angleH = " " + angleH;
669 //
670 // //lineStr = wxString::Format(sourceMask, i, amplH, freqH, angleH);
671 // atpFile.InsertLine(lineStr, cardPos);
672 // cardPos++;
673 // }
674 // }
675 //}
676
677 return true;
678}
Node for power elements. All others power elements are connected through this.
Definition Bus.h:86

◆ AddParent()

bool EMTElement::AddParent ( Element parent,
wxPoint2DDouble  position 
)
virtual

Add a parent to the element. This method must be used on power elements that connect to a bus, so the parent must be a bus. The element basic points are calculated in this method, so apply this when the element is being inserted.

Parameters
parentElement parent.
positionNode position in the parent.

Reimplemented from Element.

Definition at line 41 of file EMTElement.cpp.

42{
43 if (parent) {
44 m_parentList.push_back(parent);
45 parent->AddChild(this);
46 wxPoint2DDouble parentPt =
47 parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
48 parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
49 parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
50
51 m_position = parentPt + wxPoint2DDouble(0.0, 100.0); // Shifts the position to the down of the bus.
52 m_width = 50;
53 m_height = 50;
54 m_rect = wxRect2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0, m_width, m_height);
55
56 m_pointList.push_back(parentPt);
57 m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
58 m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0 - 10.0));
59 m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0));
60
61 m_inserted = true;
62
63 wxRect2DDouble genRect(0, 0, 0, 0);
64 m_switchRect.push_back(genRect); // Push a general rectangle.
66
67 // Base data
68 auto data = static_cast<Bus*>(parent)->GetElectricalData();
69 m_data.puVoltage = data.voltage;
70 m_data.baseVoltage = GetValueFromUnit(data.nominalVoltage, data.nominalVoltageUnit);
71 m_data.frequency = data.stabFreq;
72
73 return true;
74 }
75 return false;
76}
wxPoint2DDouble GetPosition() const
Get the element position.
Definition Element.h:188
double GetAngle() const
Get the element angle.
Definition Element.h:213
virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
Rotate a point as element position being the origin.
Definition Element.cpp:228
virtual void AddChild(Element *child)
Add a child to the child list.
Definition Element.cpp:499
virtual void UpdateSwitches()
Update the switch position.
virtual wxPoint2DDouble GetSwitchPoint(Element *parent, wxPoint2DDouble parentPoint, wxPoint2DDouble secondPoint) const
Get the correct switch position.
Here is the call graph for this function:

◆ ATPField()

wxString EMTElement::ATPField ( double  value,
size_t  width 
)
protected

Definition at line 1263 of file EMTElement.cpp.

1264{
1265 wxString best;
1266
1267 // Try fixed-point notation
1268 for (int prec = 15; prec >= 0; --prec)
1269 {
1270 wxString s = wxString::Format("%.*f", prec, value);
1271 s.Replace(",", ".");
1272
1273 while (s.Contains(".") && s.EndsWith("0"))
1274 s.RemoveLast();
1275 if (s.EndsWith("."))
1276 s.RemoveLast();
1277
1278 if (s.Length() <= width)
1279 {
1280 best = s;
1281 break;
1282 }
1283 }
1284
1285 // Try scientific notation
1286 for (int prec = 15; prec >= 0; --prec)
1287 {
1288 wxString s = wxString::Format("%.*E", prec, value);
1289 s.Replace(",", ".");
1290
1291 if (prec == 0)
1292 s.Replace("E", ".E");
1293
1294 if (s.Length() <= width)
1295 {
1296 // Keep the representation with the highest useful precision
1297 if (best.empty() || s.Length() > best.Length())
1298 best = s;
1299
1300 break;
1301 }
1302 }
1303
1304 if (best.empty())
1305 return wxString('*', width);
1306
1307 best.Prepend(wxString(' ', width - best.Length()));
1308 return best;
1309}

◆ CalculateCurrent()

bool EMTElement::CalculateCurrent ( wxString &  errorMsg,
const Mode &  mode = Mode::Phasor,
const bool &  saveRawData = false,
const bool &  saveFFTData = false 
)

Definition at line 733 of file EMTElement.cpp.

734{
735 wxFileName fileName(m_data.atpFile);
736 if (!fileName.IsOk()) {
737 errorMsg = wxString::Format(_("Invalid ATP file path for the electromagnetic element \"%s\"."), m_data.name);
738 return false;
739 }
740
741 //double fundFreq = properties.GetSimulationPropertiesData().stabilityFrequency;
742 double fundFreq = m_data.frequency;
743 double timeSim = (1.0 / fundFreq) * static_cast<double>(m_data.cyclesToSS);
744
745 //wxString atpFolder = properties.GetGeneralPropertiesData().atpPath.GetPath();
746 wxString atpFolder = m_data.atpPath.GetPath();
747 // Set fundamental frequency to EMT element
748 //m_data.frequency = fundFreq;
749
750 wxExecuteEnv env;
751 env.cwd = atpFolder;
752
753 // Save the ATP file in ATP work folder
754 wxTextFile origFile(m_data.atpFile.GetFullPath());
755 //fileName.SetPath(properties.GetGeneralPropertiesData().atpWorkFolder);
756 fileName.SetPath(m_data.atpWorkFolder);
757 wxString name = fileName.GetFullPath();
758 wxTextFile copyFile(fileName.GetFullPath());
759 if (origFile.Open()) {
760 copyFile.Create();
761 for (size_t i = 0; i < origFile.GetLineCount(); i++) {
762 copyFile.AddLine(origFile.GetLine(i));
763 }
764 origFile.Close();
765
766 wxString stepSizeStr = wxString::Format("%.2E", m_data.stepSize);
767 stepSizeStr.Replace(wxT(","), wxT("."));
768 wxString timeStr = wxString::Format("%.6f", timeSim);
769 timeStr.Replace(wxT(","), wxT("."));
770 SetATPParameter(copyFile, wxT("BEGIN NEW DATA CASE"), 1, 0, 8, stepSizeStr);
771 SetATPParameter(copyFile, wxT("BEGIN NEW DATA CASE"), 1, 8, 8, timeStr);
772 SetATPParameter(copyFile, wxT("BEGIN NEW DATA CASE"), 2, 0, 8, wxT("99999999"));
773 SetATPParameter(copyFile, wxT("BEGIN NEW DATA CASE"), 2, 8, 8, wxString::Format("%8d", m_data.recordFrequency));
774
775 // Add source and switch to selected node
776 AddConnectionToNode(copyFile, m_data.atpNodeName);
777
778 copyFile.Write();
779 }
780 else {
781 errorMsg = wxString::Format(_("Fail to open ATP file of the electromagnetic element \"%s\"."), m_data.name);
782 return false;
783 }
784
785
786 ATPPSPBridge bridge;
787
788 //wxProcess* proc = new wxProcess();
789
790 //wxString cmd = properties.GetGeneralPropertiesData().atpPath.GetFullPath() + wxT(" both ") + fileName.GetFullPath() + wxT(" s -R");
791 wxString cmd = m_data.atpPath.GetFullPath() + wxT(" both ") + fileName.GetFullPath() + wxT(" s -R");
792 long pid = wxExecute(cmd, wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_NODISABLE, nullptr, &env);
793 //long pid = wxExecute(cmd, wxEXEC_SYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_NODISABLE, nullptr, &env);
794 //long pid = wxExecute(cmd, wxEXEC_ASYNC | wxEXEC_NODISABLE, nullptr, &env);
795 //long pid = wxExecute(cmd, wxEXEC_ASYNC | wxEXEC_NODISABLE, proc, &env);
796
797 if (!bridge.Connect(5000, 100))
798 {
799 if (!CheckLISFile(fileName, errorMsg))
800 {
801 errorMsg = _("Unable to connect to ATP.\n"
802 "Please make sure you are using an ATP version with PSP support.");
803 }
804
805 return false;
806 }
807 //wxEndBusyCursor();
808 bridge.SetProcessId(pid);
809
810
811 auto& data = bridge.GetSharedData();
812 data.vrms = std::abs(m_data.puVoltage) * m_data.baseVoltage / std::sqrt(3);
813 data.phase = std::arg(m_data.puVoltage) * 180.0 / M_PI;
814 data.mode = mode;
815 //m_data.atpData.clear();
816 m_data.atpSampleData.clear();
817
818 //bridge.ReleaseATP();
819 while (bridge.WaitATP())
820 {
821 if (!saveRawData || !saveFFTData) {
822 bridge.ReleaseATP();
823 continue;
824 }
825
826 data = bridge.GetSharedData();
827
828
829 // Process ATP data
830 if (data.stepCount > 0)
831 {
832 const double dt = data.atpStepsize;
833 const double t0 = data.t - (data.stepCount - 1) * dt;
834
835 //m_data.atpData.reserve(m_data.atpData.size() + data.stepCount);
836 m_data.atpSampleData.reserve(m_data.atpSampleData.size() + data.stepCount);
837
838 std::vector<double> ia, ib, ic;
839
840 if (m_data.useMedianFilter)
841 {
842 ia.reserve(data.stepCount);
843 ib.reserve(data.stepCount);
844 ic.reserve(data.stepCount);
845
846 for (uint32_t i = 0; i < data.stepCount; ++i)
847 {
848 ia.push_back(data.samples[i].current[0]);
849 ib.push_back(data.samples[i].current[1]);
850 ic.push_back(data.samples[i].current[2]);
851 }
852
853 MedianFilter(ia);
854 MedianFilter(ib);
855 MedianFilter(ic);
856 }
857
858 for (uint32_t i = 0; i < data.stepCount; ++i)
859 {
860 const double t = t0 + i * dt;
861
862 const double currentA = m_data.useMedianFilter ? -ia[i] : -data.samples[i].current[0];
863 const double currentB = m_data.useMedianFilter ? -ib[i] : -data.samples[i].current[1];
864 const double currentC = m_data.useMedianFilter ? -ic[i] : -data.samples[i].current[2];
865
866 const double iaMag = std::hypot(-data.phasor.Id[0], -data.phasor.Iq[0]);
867 const double ibMag = std::hypot(-data.phasor.Id[1], -data.phasor.Iq[1]);
868 const double icMag = std::hypot(-data.phasor.Id[2], -data.phasor.Iq[2]);
869 const double iaAng = std::atan2(-data.phasor.Iq[0], -data.phasor.Id[0]);
870 const double ibAng = std::atan2(-data.phasor.Iq[1], -data.phasor.Id[1]);
871 const double icAng = std::atan2(-data.phasor.Iq[2], -data.phasor.Id[2]);
872
873 //m_data.atpData.emplace_back(t, currentA);
874 m_data.atpSampleData.push_back({
875 .t = t,
876 .current = { currentA, currentB, currentC },
877 .mag = {iaMag, ibMag, icMag},
878 .angle = {iaAng, ibAng, icAng}
879 });
880 }
881 }
882
883 bridge.ReleaseATP();
884 }
885
886 if (data.terminate < 0)
887 {
888 CheckLISFile(fileName, errorMsg);
889 return false;
890 }
891 constexpr size_t phase = 0; // 0 = A, 1 = B, 2 = C
892
893 // Save current
894 m_data.current = std::complex<double>(-data.phasor.Id[phase], -data.phasor.Iq[phase]);
895
896 // Delete all .tmp files
897 wxDir dir(atpFolder);
898 if (dir.IsOpened()) {
899 wxString file;
900 bool cont = dir.GetFirst(&file, wxT("*.tmp"), wxDIR_FILES);
901 while (cont) {
902 wxRemoveFile(atpFolder + wxT("/") + file);
903 cont = dir.GetNext(&file);
904 }
905 }
906
907 if (saveFFTData)
908 {
909 // FFT
910 double dataStepSize = m_data.atpSampleData[1].t - m_data.atpSampleData[0].t;
911 bool useRemainder = false;
912 size_t sampleCount = m_data.atpSampleData.size();
913 size_t n = static_cast<size_t>(std::ceil(1.0 / (dataStepSize * fundFreq)));
914
915 // Due to ATP logic, the number of samples can be greater than the number
916 // of samples stored. In this case, follow the remainder approach.
917 if (n > sampleCount)
918 {
919 n = sampleCount;
920 useRemainder = true;
921 }
922
923 double fs = 1.0 / dataStepSize;
924 double df = fs / static_cast<double>(n);
925
926 if (useRemainder) {
927 double rmder = std::abs(std::remainder(fundFreq, df));
928 size_t minRmderN = n;
929
930 while (rmder > 1e-3)
931 {
932 --n;
933 df = fs / static_cast<double>(n);
934 if (std::abs(std::remainder(fundFreq, df)) < rmder)
935 minRmderN = n;
936
937 rmder = std::abs(std::remainder(fundFreq, df));
938 if (n == 0) {
939 n = minRmderN;
940 df = fs / static_cast<double>(n);
941 break;
942 }
943 }
944 }
945
946 double dtWindow = m_data.atpSampleData.back().t - m_data.atpSampleData[sampleCount - n].t;
947
948 fftw_complex* out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (n / 2 + 1));
949
950 double* in = (double*)fftw_malloc(sizeof(double) * n);
951
952 // Populate FFT input
953 const size_t first = sampleCount - n;
954 for (size_t i = 0; i < n; ++i) {
955 in[i] = m_data.atpSampleData[first + i].current[phase];
956 }
957
958 fftw_plan p = fftw_plan_dft_r2c_1d(n, in, out, FFTW_ESTIMATE);
959
960 fftw_execute(p);
961 fftw_destroy_plan(p);
962
963 double ampCorrection = 2.0 / static_cast<double>(n);
964
965 // Identify fundamental frequency
966 int fundIndex = -1;
967 double fundMagnitude = 0.0;
968
969 for (size_t i = 0; i < (n / 2 + 1); ++i) {
970 double freq = static_cast<double>(i) * df;
971
972 if (std::remainder(freq, fundFreq)) {
973 fundIndex = static_cast<int>(i);
974
975 fundMagnitude =
976 std::hypot(out[i][0], out[i][1]) * ampCorrection;
977
978 break;
979 }
980 }
981
982 if (fundIndex < 0) {
983 errorMsg = wxString::Format(_("Fail to identify the fundamental frequency of the electromagnetic element \"%s\"."), m_data.name);
984
985 fftw_free(in);
986 fftw_free(out);
987
988 return false;
989 }
990
991 // Fundamental and harmonics
992 m_data.currHarmonics.clear();
993
994 for (size_t i = 0; i < (n / 2 + 1); ++i) {
995 double freq = static_cast<double>(i) * df;
996 int order = static_cast<int>(std::round(freq / fundFreq));
997
998 if (order > m_data.numMaxHarmonics)
999 break;
1000
1001 double magnitude = std::hypot(out[i][0], out[i][1]) * ampCorrection;
1002
1003 if ((magnitude / fundMagnitude) > (m_data.harmonicsThreshold / 100.0)) {
1004 m_data.currHarmonics[order] =
1005 std::complex<double>(out[i][0], out[i][1]) *
1006 ampCorrection / std::sqrt(2.0);
1007 }
1008 }
1009
1010 m_data.inFFTData.clear();
1011 m_data.outFFTData.clear();
1012
1013 for (size_t i = 0; i < n; ++i)
1014 {
1015 m_data.inFFTData.emplace_back(m_data.atpSampleData[first + i].t, in[i]);
1016 }
1017
1018 for (size_t i = 0; i < (n / 2 + 1); ++i)
1019 {
1020 std::complex<double> value(out[i][0] * ampCorrection, out[i][1] * ampCorrection);
1021 double freq = static_cast<double>(i) * df;
1022 m_data.outFFTData.emplace_back(freq, value);
1023 }
1024
1025 fftw_free(in);
1026 fftw_free(out);
1027 }
1028
1029 return true;
1030
1031 errorMsg = "Not implemented yet.\n EMTElement.cpp, line 772ish";
1032 return false;
1033
1034 fileName.SetFullName(fileName.GetName() + wxT(".pl4"));
1035 wxFileInputStream pl4File(fileName.GetFullPath());
1036 // https://github.com/ldemattos/readPL4/wiki/PISA's-PL4-Format---Time-domain
1037 if (pl4File.IsOk() && pl4File.GetSize() > 0) {
1038 wxDataInputStream store(pl4File);
1039 store.UseBasicPrecisions();
1040 float* buffer = new float[2];
1041 std::vector<double> timeVec;
1042 std::vector<double> valueVec;
1043 double oldTime = 0.0;
1044 int read16Bytes = 0;
1045 while (!pl4File.Eof()) {
1046 store.ReadFloat(buffer, 2);
1047 if (read16Bytes > 11 && (buffer[0] >= oldTime)) {
1048 oldTime = buffer[0];
1049 timeVec.emplace_back(buffer[0]);
1050 valueVec.emplace_back(buffer[1]);
1051 }
1052 read16Bytes++;
1053 }
1054 delete[] buffer;
1055
1056 if (m_data.useMedianFilter)
1057 MedianFilter(valueVec);
1058
1059 // FFT
1060 double dataStepSize = timeVec[1] - timeVec[0]; // Real sampling time from data
1061 bool useRemainder = false;
1062 size_t n = ceil(1.0 / (dataStepSize * fundFreq)); // Number of samples
1063 // Due to ATP logic, the number of samples can be greater than the number of samples in the PL4 file
1064 // In this case, I choose to follow the remainder approach
1065 if (n > valueVec.size()) {
1066 n = valueVec.size();
1067 useRemainder = true;
1068 }
1069
1070 double fs = 1.0 / dataStepSize; // Sampling frequency
1071 double df = fs / static_cast<double>(n); // Frequency resolution
1072
1073 if (useRemainder) {
1074 double rmder = abs(remainder(fundFreq, df));
1075 int minRmderN = n;
1076 while (rmder > 1e-3) {
1077 n--;
1078 df = fs / static_cast<double>(n);
1079
1080 if (abs(remainder(fundFreq, df)) < rmder) minRmderN = n;
1081
1082 rmder = abs(remainder(fundFreq, df));
1083
1084 if (n <= 0) {
1085 n = minRmderN;
1086 df = fs / static_cast<double>(n);
1087 break;
1088 }
1089 }
1090 }
1091
1092 double dtWindow = timeVec[timeVec.size() - 1] - timeVec[timeVec.size() - n];
1093
1094 fftw_complex* out;
1095 double* in;
1096 fftw_plan p;
1097 out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * (n / 2 + 1));
1098 in = (double*)fftw_malloc(sizeof(double) * n);
1099 // Populate input array
1100 for (size_t i = (valueVec.size() - n); i < valueVec.size(); ++i) {
1101 size_t index = i - (valueVec.size() - n);
1102 in[index] = valueVec[i];
1103 }
1104
1105 p = fftw_plan_dft_r2c_1d(n, in, out, FFTW_ESTIMATE);
1106 fftw_execute(p); /* repeat as needed */
1107 fftw_destroy_plan(p);
1108
1109 double ampCorrection = 2.0 / static_cast<double>(n);
1110
1111 // Identify fundamental frequency
1112 int fundIndex = -1;
1113 double fundMagnitude = 0.0;
1114 for (size_t i = 0; i < (n / 2 + 1); i++) {
1115 double freq = static_cast<double>(i) * df;
1116 if (remainder(freq, fundFreq)) {
1117 fundIndex = i;
1118 fundMagnitude = sqrt(out[i][0] * out[i][0] + out[i][1] * out[i][1]) * ampCorrection;
1119 break;
1120 }
1121 }
1122 if (fundIndex < 0) {
1123 errorMsg = wxString::Format(_("Fail to identify the fundamental frequency of the electromagnetic element \"%s\"."), m_data.name);
1124 return false;
1125 }
1126
1127 // Fundamental and harmonics
1128 m_data.currHarmonics.clear();
1129 //m_data.currHarmonicsOrder.clear();
1130 for (size_t i = 0; i < (n / 2 + 1); i++) {
1131 double freq = static_cast<double>(i) * df;
1132 int order = static_cast<int>(round(freq / fundFreq));
1133
1134 if (order > m_data.numMaxHarmonics) break; // Stop if the order is greater than the maximum number of harmonics
1135
1136 double magnitude = sqrt(out[i][0] * out[i][0] + out[i][1] * out[i][1]) * ampCorrection;
1137 if ((magnitude / fundMagnitude) > (m_data.harmonicsThreshold / 100.0)) {
1138 //m_data.currHarmonics.emplace_back(std::complex<double>(out[i][0], out[i][1]) * ampCorrection);
1139 //m_data.currHarmonicsOrder.emplace_back(order);
1140 m_data.currHarmonics[order] = std::complex<double>(out[i][0], out[i][1]) * ampCorrection / sqrt(2.0); // RMS value
1141 }
1142 }
1143
1144 //if (saveFFTData) {
1145 // m_data.atpData.clear();
1146 // m_data.inFFTData.clear();
1147 // m_data.outFFTData.clear();
1148 // for (size_t i = 0; i < valueVec.size(); i++) {
1149 // m_data.atpData.emplace_back(std::make_pair(timeVec[i], valueVec[i]));
1150 // }
1151 // for (size_t i = 0; i < n; i++) {
1152 // m_data.inFFTData.emplace_back(std::make_pair(timeVec[i + timeVec.size() - n], in[i]));
1153 // }
1154 // for (size_t i = 0; i < (n / 2 + 1); i++) {
1155 // std::complex<double> value(out[i][0] * ampCorrection, out[i][1] * ampCorrection);
1156 // double freq = static_cast<double>(i) * df;
1157 // m_data.outFFTData.emplace_back(std::make_pair(freq, value));
1158 // }
1159 //}
1160 //
1161 fftw_free(in);
1162 fftw_free(out);
1163
1164 }
1165 else {
1166 wxString atpErrorMsg = _("No error found.");
1167
1168 fileName.SetFullName(fileName.GetName() + wxT(".lis"));
1169 wxTextFile lisFile(fileName.GetFullPath());
1170
1171 if (!lisFile.Exists()) {
1172 errorMsg = wxString::Format(_("Fail to run ATP file of the electromagnetic element \"%s\".\nThe ATP program did not return any error messages."), m_data.name);
1173 return false;
1174 }
1175 if (lisFile.Open()) {
1176 wxString line = lisFile.GetFirstLine() + "\n";
1177 bool foundError = false;
1178 int lineCount = -1;
1179 atpErrorMsg.Clear();
1180 while (!lisFile.Eof())
1181 {
1182 if (line.Find(wxT("KILL ")) != wxNOT_FOUND) {
1183 foundError = true;
1184 lineCount++;
1185 }
1186 if (line.Find(wxT("----------")) != wxNOT_FOUND) {
1187 foundError = false;
1188 }
1189 if (foundError && lineCount == 1)
1190 atpErrorMsg += line + " ";
1191 line = lisFile.GetNextLine();
1192 }
1193 lisFile.Close();
1194 }
1195 else
1196 {
1197 errorMsg = wxString::Format(_("Fail to run ATP file of the electromagnetic element \"%s\".\nThe ATP program did not return any error messages."), m_data.name);
1198 return false;
1199 }
1200
1201 errorMsg = wxString::Format(_("Fail to run ATP file of the electromagnetic element \"%s\".\nThe ATP returned the following error message:\n\"%s\""), m_data.name, atpErrorMsg);
1202 return false;
1203 }
1204 return true;
1205}

◆ CheckLISFile()

bool EMTElement::CheckLISFile ( wxFileName  fileName,
wxString &  errorMsg 
) const
protected

Definition at line 1311 of file EMTElement.cpp.

1312{
1313 wxString atpErrorMsg = _("No error found.");
1314
1315 fileName.SetFullName(fileName.GetName() + wxT(".lis"));
1316 wxTextFile lisFile(fileName.GetFullPath());
1317
1318 if (!lisFile.Exists()) {
1319 errorMsg = wxString::Format(_("Fail to run ATP file of the electromagnetic element \"%s\".\nThe ATP program did not return any error messages."), m_data.name);
1320 return false;
1321 }
1322 if (lisFile.Open()) {
1323 wxString line = lisFile.GetFirstLine() + "\n";
1324 bool foundError = false;
1325 int lineCount = -1;
1326 atpErrorMsg.Clear();
1327 while (!lisFile.Eof())
1328 {
1329 if (line.Find(wxT("KILL ")) != wxNOT_FOUND) {
1330 foundError = true;
1331 lineCount++;
1332 }
1333 if (line.Find(wxT("----------")) != wxNOT_FOUND) {
1334 foundError = false;
1335 }
1336 if (foundError && lineCount == 1)
1337 atpErrorMsg += line + " ";
1338 line = lisFile.GetNextLine();
1339 }
1340 lisFile.Close();
1341 }
1342 else
1343 {
1344 errorMsg = wxString::Format(_("Fail to run ATP file of the electromagnetic element \"%s\".\nThe ATP program did not return any error messages."), m_data.name);
1345 return true;
1346 }
1347
1348 errorMsg = wxString::Format(_("Fail to run ATP file of the electromagnetic element \"%s\".\nThe ATP returned the following error message:\n\"%s\""), m_data.name, atpErrorMsg);
1349 return true;
1350}

◆ Contains()

virtual bool EMTElement::Contains ( wxPoint2DDouble  position) const
inlinevirtual

Checks if the element contains a position.

Parameters
positionPosition to be checked.

Reimplemented from Shunt.

Definition at line 93 of file EMTElement.h.

93{ return m_rect.Contains(position); }

◆ DoMedianFilter()

void EMTElement::DoMedianFilter ( double *  extension,
std::vector< double > &  result,
const int &  n 
)
protected

Definition at line 1237 of file EMTElement.cpp.

1238{
1239 // Move window through all elements of the signal
1240 for (int i = 2; i < n - 2; ++i)
1241 {
1242 // Pick up window elements
1243 double window[5];
1244 for (int j = 0; j < 5; ++j)
1245 window[j] = extension[i - 2 + j];
1246 // Order elements (only half of them)
1247 for (int j = 0; j < 3; ++j)
1248 {
1249 // Find position of minimum element
1250 int min = j;
1251 for (int k = j + 1; k < 5; ++k)
1252 if (window[k] < window[min])
1253 min = k;
1254 // Put found minimum element in its place
1255 std::swap(window[j], window[min]);
1256 }
1257 // Get result - the middle element
1258 result[i - 2] = window[2];
1259 }
1260 //return result;
1261}

◆ DrawDC() [1/2]

void EMTElement::DrawDC ( GUIColour guiColour,
wxPoint2DDouble  translation,
double  scale,
wxDC &  dc 
) const
virtual

Draw the element using wxDC.

Parameters
guiColourColours of the system defined in properties.
translationTranslation of the system.
scaleScale of the system.
dcDevice context.

Reimplemented from Element.

Definition at line 162 of file EMTElement.cpp.

163{
164 wxColour elementColour;
165 if (m_online) {
166 if (m_dynEvent)
167 elementColour = guiColour->eventElement;
168 else
169 elementColour = guiColour->enabled;
170 }
171 else
172 elementColour = guiColour->disable;
173
174 std::vector<wxPoint> pointListInt;
175 for (auto& pt : m_pointList) {
176 pointListInt.emplace_back(static_cast<int>(pt.m_x), static_cast<int>(pt.m_y));
177 }
178
179 if (m_inserted) {
180
181 if (m_selected) {
182 dc.SetPen(wxPen(guiColour->selection, 2 + m_borderSize * 2.0));
183 dc.SetBrush(*wxTRANSPARENT_BRUSH);
184
185 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
186
187 DrawDCRoundedRectRotated(dc, m_position, m_width, m_height, 10.0, m_angle);
188
189 // Draw node selection.
190 dc.SetPen(*wxTRANSPARENT_PEN);
191 dc.SetBrush(wxBrush(guiColour->selection));
192 DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, dc);
193 }
194 // Draw EMTElement (layer 2).
195 // Draw node.
196 dc.SetPen(*wxTRANSPARENT_PEN);
197 dc.SetBrush(wxBrush(elementColour));
198 DrawDCCircle(pointListInt[0], 5.0, dc);
199
200 dc.SetPen(wxPen(elementColour, 2));
201 dc.SetBrush(*wxTRANSPARENT_BRUSH);
202 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
203
204 DrawDCSwitches(guiColour, dc);
205
206 dc.SetPen(wxPen(elementColour, 2));
207 dc.SetBrush(wxBrush(guiColour->background));
208 DrawDCRoundedRectRotated(dc, m_position, m_width, m_height, 10.0, m_angle);
209
210 wxFont font;
211 font.SetFaceName(wxT("CMU Serif"));
212 font.SetPointSize(10);
213 font.MakeBold();
214 GCText gcText;
215 gcText.SetFont(font);
216 gcText.SetText(_("EMT"));
217 wxPoint pt = RotateAround(m_position + wxPoint2DDouble(0.0, 20.0), m_position, m_angle);
218 gcText.Draw(pt, gcText.GetWidth(), gcText.GetHeight(), dc, m_angle, m_online ? wxColour(255, 60, 0) : m_offlineElementColour);
219
220 dc.SetPen(wxPen(m_online ? wxColour(0, 60, 255) : m_offlineElementColour, 2));
221 std::vector<wxPoint> ptList;
222 for (double x = m_position.m_x - m_width / 2.0 + 2; x < (m_position.m_x + m_width / 2.0); x += (m_width - 4.0) / 6.0) {
223 wxPoint pt = RotateAround(wxPoint2DDouble(x, m_position.m_y + std::sin((x - (m_position.m_x - m_width / 2.0 + 2)) / m_width * 6 * M_PI) * 20.0), m_position, m_angle);
224 ptList.emplace_back(pt);
225 }
226 dc.DrawSpline(ptList.size(), ptList.data());
227 }
228}
virtual void DrawDCCircle(wxPoint2DDouble position, double radius, int numSegments, wxGraphicsContext *gc) const
Draw a circle using device context.
Definition Element.cpp:173
Class to draw text on Graphics Context using wxWidgets.
Definition GCText.h:32
virtual void Draw(wxPoint2DDouble position, wxGraphicsContext *gc, double angle=0.0, wxColour colour= *wxBLACK) const
Draw the text in wxGraphicsContext.
Definition GCText.cpp:35
virtual void SetText(wxString text)
Set correctly a new text string.
Definition GCText.cpp:68
virtual void DrawDCSwitches(GUIColour *guiColour, wxGraphicsContext *gc) const
Draw switch.
Here is the call graph for this function:

◆ DrawDC() [2/2]

void EMTElement::DrawDC ( GUIColour guiColour,
wxPoint2DDouble  translation,
double  scale,
wxGraphicsContext *  gc 
) const
virtual

Draw the element using GDI+.

Parameters
guiColourColours of the system defined in properties.
translationTranslation of the system.
scaleScale of the system.
gcGraphics context

Reimplemented from Element.

Definition at line 78 of file EMTElement.cpp.

79{
80 wxColour elementColour;
81 if (m_online) {
82 if (m_dynEvent)
83 elementColour = guiColour->eventElement;
84 else
85 elementColour = guiColour->enabled;
86 }
87 else
88 elementColour = guiColour->disable;
89
90 if (m_inserted) {
91
92 if (m_selected) {
93 gc->SetPen(wxPen(guiColour->selection, 2.0 + m_borderSize * 2.0));
94 gc->SetBrush(*wxTRANSPARENT_BRUSH);
95
96 gc->StrokeLines(m_pointList.size(), &m_pointList[0]);
97
98 // Push the current matrix on stack.
99 gc->PushState();
100 // Rotate the matrix around the object position.
101 gc->Translate(m_position.m_x, m_position.m_y);
102 gc->Rotate(wxDegToRad(m_angle));
103 gc->Translate(-m_position.m_x, -m_position.m_y);
104
105 //gc->DrawRectangle(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0, m_width, m_height);
106 gc->DrawRoundedRectangle(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0, m_width, m_height, 10.0);
107
108 gc->PopState();
109
110 // Draw node selection.
111 gc->SetPen(*wxTRANSPARENT_PEN);
112 gc->SetBrush(wxBrush(guiColour->selection));
113 DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, gc);
114 }
115 // Draw EMTElement (layer 2).
116 // Draw node.
117 gc->SetPen(*wxTRANSPARENT_PEN);
118 gc->SetBrush(wxBrush(elementColour));
119 DrawDCCircle(m_pointList[0], 5.0, 10, gc);
120
121 gc->SetPen(wxPen(elementColour, 2));
122 gc->SetBrush(*wxTRANSPARENT_BRUSH);
123 gc->StrokeLines(m_pointList.size(), &m_pointList[0]);
124
125 DrawDCSwitches(guiColour, gc);
126
127 // Push the current matrix on stack.
128 gc->PushState();
129 // Rotate the matrix around the object position.
130 gc->Translate(m_position.m_x, m_position.m_y);
131 gc->Rotate(wxDegToRad(m_angle));
132 gc->Translate(-m_position.m_x, -m_position.m_y);
133
134 gc->SetPen(wxPen(elementColour, 2));
135 gc->SetBrush(wxBrush(guiColour->background));
136 //gc->DrawRectangle(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0, m_width, m_height);
137 gc->DrawRoundedRectangle(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0, m_width, m_height, 10.0);
138
139 //gc->SetPen(*wxBLACK_PEN);
140 //wxFont font(10, wxFONTFAMILY_ROMAN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
141 wxFont font;
142 font.SetFaceName(wxT("CMU Serif"));
143 font.SetPointSize(10);
144 font.MakeBold();
145 gc->SetFont(font, m_online ? wxColour(255, 60, 0) : m_offlineElementColour);
146 double textWidth, textHeight;
147 gc->GetTextExtent(_("EMT"), &textWidth, &textHeight);
148 gc->DrawText(_("EMT"), m_position.m_x - textWidth / 2.0, m_position.m_y - textHeight / 2.0 + 20.0);
149
150 wxGCDC* gcdc = new wxGCDC(gc);
151 gcdc->SetPen(wxPen(m_online ? wxColour(0, 60, 255) : m_offlineElementColour, 2));
152 std::vector<wxPoint> ptList;
153 for (double x = m_position.m_x - m_width / 2.0 + 2; x < (m_position.m_x + m_width / 2.0); x += (m_width - 4.0) / 6.0) {
154 ptList.emplace_back(x, m_position.m_y + std::sin((x - (m_position.m_x - m_width / 2.0 + 2)) / m_width * 6 * M_PI) * 20.0);
155 }
156 gcdc->DrawSpline(ptList.size(), ptList.data());
157
158 gc->PopState();
159 }
160}
Here is the call graph for this function:

◆ GetATPNodes()

wxArrayString EMTElement::GetATPNodes ( wxArrayString  atpFile)

Definition at line 338 of file EMTElement.cpp.

339{
340 wxArrayString nodeList;
341 uint32_t mode = 0;
342 std::vector<wxString> mode0Cards{ "/OUTPUT", "BLANK", "TACS", "INCLUDE", "TRANSFORMER" };
343 std::vector<wxString> mode1Cards{ "/SOURCE" };
344 std::vector<wxString> mode2Cards{ "/BRANCH", "/SWITCH", };
345 wxString ground = "000000";
346 for (wxString line : atpFile) {
347 if (line.IsEmpty()) continue;
348 if (tolower(line[0]) == 'c') continue; // Skip comments
349
350 bool cardHeader = false;
351 for (wxString card : mode0Cards) {
352 if (line.Find(card) != wxNOT_FOUND) {
353 mode = 0;
354 cardHeader = true;
355 break;
356 }
357 }
358 for (wxString card : mode1Cards) {
359 if (line.Find(card) != wxNOT_FOUND) {
360 mode = 1;
361 cardHeader = true;
362 break;
363 }
364 }
365 for (wxString card : mode2Cards) {
366 if (line.Find(card) != wxNOT_FOUND) {
367 mode = 2;
368 cardHeader = true;
369 break;
370 }
371 }
372 if (cardHeader) continue;
373
374
375 wxString node = "";
376 switch (mode)
377 {
378 case 1: {
379 node = line(2, 6).Trim();
380 node.Replace(" ", "0");
381 if (node != ground && node[5] >= 'A') { // Ignore ground and monophasic nodes
382 if (nodeList.Index(node(0, 5)) == wxNOT_FOUND)
383 nodeList.Add(node(0, 5));
384 }
385 } break;
386 case 2: {
387 node = line(2, 6);
388 if (node != ground && node[5] >= 'A') { // Ignore ground and monophasic nodes
389 if (nodeList.Index(node(0, 5)) == wxNOT_FOUND)
390 nodeList.Add(node(0, 5));
391 }
392 node = line(8, 6);
393 if (node != ground && node[5] >= 'A') { // Ignore ground and monophasic nodes
394 if (nodeList.Index(node(0, 5)) == wxNOT_FOUND)
395 nodeList.Add(node(0, 5));
396 }
397 } break;
398 }
399 }
400 return nodeList;
401}

◆ GetContextMenu()

bool EMTElement::GetContextMenu ( wxMenu &  menu)
virtual

Get the element contex menu.

Parameters
menumenu that will be inserted the element itens.
Returns
True if was possible to build the menu, false otherwise.

Reimplemented from Element.

Definition at line 242 of file EMTElement.cpp.

243{
244 menu.Append(ID_EDIT_ELEMENT, _("Edit Electromagnetic Transient"));
245 GeneralMenuItens(menu);
246 return true;
247}
@ ID_EDIT_ELEMENT
Definition Element.h:77
virtual void GeneralMenuItens(wxMenu &menu)
Insert general itens to context menu.
Definition Element.cpp:393
Here is the call graph for this function:

◆ GetCopy()

Element * EMTElement::GetCopy ( )
virtual

Get a the element copy.

Returns
Copy of the element.

Reimplemented from Element.

Definition at line 34 of file EMTElement.cpp.

35{
36 EMTElement* copy = new EMTElement();
37 *copy = *this;
38 return copy;
39}
Element to connect ATP-EMTP.
Definition EMTElement.h:83

◆ GetEMTElementData()

virtual EMTElementData EMTElement::GetEMTElementData ( )
inlinevirtual

Definition at line 103 of file EMTElement.h.

103{ return m_data; }

◆ GetTipText()

wxString EMTElement::GetTipText ( ) const
virtual

Get the tip text.

Returns
Tip text.

Reimplemented from Element.

Definition at line 249 of file EMTElement.cpp.

250{
251 wxString tipText = m_data.name;
252 tipText += wxT("\n");
253
254 tipText += wxString::Format(_("\nP = %.5f p.u."), m_data.power.real());
255 tipText += wxString::Format(_("\nQ = %.5f p.u."), m_data.power.imag());
256 if (auto itCurrrent = m_data.currHarmonics.find(1); itCurrrent != m_data.currHarmonics.end())
257 tipText += wxString::Format(_("\nI = %.5f A"), std::abs(itCurrrent->second));
258
259 wxString harmonicsInfo = _("\n\nHarmonics info:");
260 bool hasHarmonics = false;
261 for (auto& [order, current] : m_data.currHarmonics) {
262 if (order != 1) {
263 hasHarmonics = true;
264 harmonicsInfo += wxString::Format(_("\nIh(%d): %.5f%s%.2f%s A"), order, std::abs(current), wxString(L'\u2220'), wxRadToDeg(std::arg(current)), wxString(L'\u00B0'));
265 }
266 }
267
268 if (hasHarmonics) tipText += harmonicsInfo;
269
270 return tipText;
271}

◆ Intersects()

virtual bool EMTElement::Intersects ( wxRect2DDouble  rect) const
inlinevirtual

Check if the element's rect intersects other rect.

Parameters
rectRect to check intersection.

Reimplemented from Shunt.

Definition at line 94 of file EMTElement.h.

94{ return m_rect.Intersects(rect); }

◆ MedianFilter()

void EMTElement::MedianFilter ( std::vector< double > &  data)

Definition at line 680 of file EMTElement.cpp.

681{
682 // Based on: http://www.librow.com/articles/article-1
683
684 const size_t n = data.size();
685
686 if (n < 2)
687 return;
688
689 std::vector<double> extension(n + 4);
690
691 std::memcpy(extension.data() + 2, data.data(), n * sizeof(double));
692
693 extension[0] = data[1];
694 extension[1] = data[0];
695 extension[n + 2] = data[n - 1];
696 extension[n + 3] = data[n - 2];
697
698 DoMedianFilter(extension.data(), data, static_cast<int>(n + 4));
699
700 //size_t n = data.size();
701 //std::vector<double> result(data);
702 //
704 //if (data.empty() || n < 1)
705 // return result;
707 //if (n == 1)
708 //{
709 // result[0] = data[0];
710 // return result;
711 //}
713 //double* extension = new double[n + 4];
718 //memcpy(extension + 2, data.data(), n * sizeof(double));
719 //for (int i = 0; i < 2; ++i)
720 //{
721 // extension[i] = data[1 - i];
722 // extension[n + 2 + i] = data[n - 1 - i];
723 //}
725 // DoMedianFilter(extension, result, n + 4);
728 //delete[] extension;
729 //
730 //return result;
731}

◆ OpenElement()

bool EMTElement::OpenElement ( rapidxml::xml_node<> *  elementNode,
std::vector< Element * >  parentList 
)
virtual

Reimplemented from PowerElement.

Definition at line 317 of file EMTElement.cpp.

318{
319 if (!OpenCADProperties(elementNode, parentList)) return false;
320
321 auto electricalProp = elementNode->first_node("ElectricalProperties");
322 if (!electricalProp) return false;
323
324 SetOnline(XMLParser::GetNodeValueInt(electricalProp, "IsOnline"));
325 m_data.name = electricalProp->first_node("Name")->value();
326 m_data.atpFile = wxFileName(electricalProp->first_node("ATPFilePath")->value());
327 m_data.atpNodeName = electricalProp->first_node("ATPNodeName")->value();
328 m_data.stepSize = XMLParser::GetNodeValueDouble(electricalProp, "StepSize");
329 m_data.cyclesToSS = XMLParser::GetNodeValueInt(electricalProp, "CyclesToSS");
330 m_data.recordFrequency = XMLParser::GetNodeValueInt(electricalProp, "RecordFrequency");
331 m_data.useMedianFilter = XMLParser::GetNodeValueInt(electricalProp, "UseMedianFilter");
332 m_data.numMaxHarmonics = XMLParser::GetNodeValueInt(electricalProp, "NumMaxHarmonics");
333
334 m_inserted = true;
335 return true;
336}
bool SetOnline(bool online=true)
Set if the element is online or offline.
Definition Element.cpp:383

◆ Rotate()

void EMTElement::Rotate ( bool  clockwise = true)
virtual

Rotate the element.

Parameters
clockwiseTrue to rotate clockwise, false to rotate counter-clockwise.

Reimplemented from Element.

Definition at line 230 of file EMTElement.cpp.

231{
232 double rotAngle = m_rotationAngle;
233 if (!clockwise) rotAngle = -m_rotationAngle;
234
235 m_angle += rotAngle;
236 if (m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
237 m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
238 m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
239 UpdateSwitchesPosition();
240}
Here is the call graph for this function:

◆ SaveElement()

rapidxml::xml_node * EMTElement::SaveElement ( rapidxml::xml_document<> &  doc,
rapidxml::xml_node<> *  elementListNode 
)
virtual

Reimplemented from Element.

Definition at line 287 of file EMTElement.cpp.

288{
289 auto elementNode = XMLParser::AppendNode(doc, elementListNode, "EMTElement");
290 XMLParser::SetNodeAttribute(doc, elementNode, "ID", m_elementID);
291
292 SaveCADProperties(doc, elementNode);
293
294 auto electricalProp = XMLParser::AppendNode(doc, elementNode, "ElectricalProperties");
295 auto isOnline = XMLParser::AppendNode(doc, electricalProp, "IsOnline");
296 XMLParser::SetNodeValue(doc, isOnline, m_online);
297 auto name = XMLParser::AppendNode(doc, electricalProp, "Name");
298 XMLParser::SetNodeValue(doc, name, m_data.name);
299 auto atpFilePath = XMLParser::AppendNode(doc, electricalProp, "ATPFilePath");
300 XMLParser::SetNodeValue(doc, atpFilePath, m_data.atpFile.GetFullPath());
301 auto atpNodeName = XMLParser::AppendNode(doc, electricalProp, "ATPNodeName");
302 XMLParser::SetNodeValue(doc, atpNodeName, m_data.atpNodeName);
303 auto stepSize = XMLParser::AppendNode(doc, electricalProp, "StepSize");
304 XMLParser::SetNodeValue(doc, stepSize, m_data.stepSize);
305 auto cyclesToSS = XMLParser::AppendNode(doc, electricalProp, "CyclesToSS");
306 XMLParser::SetNodeValue(doc, cyclesToSS, m_data.cyclesToSS);
307 auto recordFrequency = XMLParser::AppendNode(doc, electricalProp, "RecordFrequency");
308 XMLParser::SetNodeValue(doc, recordFrequency, m_data.recordFrequency);
309 auto useMedianFilter = XMLParser::AppendNode(doc, electricalProp, "UseMedianFilter");
310 XMLParser::SetNodeValue(doc, useMedianFilter, m_data.useMedianFilter);
311 auto numMaxHarmonics = XMLParser::AppendNode(doc, electricalProp, "NumMaxHarmonics");
312 XMLParser::SetNodeValue(doc, numMaxHarmonics, m_data.numMaxHarmonics);
313
314 return elementNode;
315}

◆ SetATPParameter()

bool EMTElement::SetATPParameter ( wxTextFile &  atpFile,
const wxString &  card,
const int &  line,
const int &  initPos,
const int &  size,
const wxString &  value 
)

Definition at line 403 of file EMTElement.cpp.

404{
405 bool foundCard = false;
406 int currLine = -1;
407 wxString lineStr = "";
408 lineStr = atpFile.GetFirstLine();
409 while (!atpFile.Eof())
410 {
411 if (tolower(lineStr[0]) == 'c') {
412 lineStr = atpFile.GetNextLine();
413 continue; // Skip comments
414 }
415 if (lineStr.Find(card) != wxNOT_FOUND) {
416 foundCard = true;
417 currLine = -1;
418 }
419 if (foundCard) currLine++;
420 if (foundCard && currLine == line) {
421 for (int i = initPos; i < initPos + size; i++) {
422 lineStr[i] = value[i - initPos];
423 }
424 atpFile.RemoveLine(atpFile.GetCurrentLine());
425 atpFile.InsertLine(lineStr, atpFile.GetCurrentLine());
426 return true;
427 }
428
429 lineStr = atpFile.GetNextLine();
430 }
431 return false;
432}

◆ SetEMTElementData()

virtual void EMTElement::SetEMTElementData ( EMTElementData  data)
inlinevirtual

Definition at line 104 of file EMTElement.h.

104{ m_data = data; }

◆ SetNominalVoltage()

void EMTElement::SetNominalVoltage ( std::vector< double >  nominalVoltage,
std::vector< ElectricalUnit >  nominalVoltageUnit 
)
virtual

Set nominal voltage of the element.

Parameters
nominalVoltageValue of the nominal voltage.
nominalVoltageUnitUnit of the nominal voltage.

Reimplemented from PowerElement.

Definition at line 1230 of file EMTElement.cpp.

1231{
1232 if (!nominalVoltage.empty()) {
1233 m_data.baseVoltage = GetValueFromUnit(nominalVoltage[0], nominalVoltageUnit[0]);
1234 }
1235}

◆ ShowForm()

bool EMTElement::ShowForm ( wxWindow *  parent,
Element element,
wxWindow *  workspace = nullptr 
)
virtual

Show element data form.

Parameters
parentForm parent
elementElement that will be edited.
Returns
True if the form is shown, false otherwise.

Reimplemented from Element.

Definition at line 273 of file EMTElement.cpp.

274{
275 Workspace* ws = dynamic_cast<Workspace*>(workspace);
276 if (!ws) return false;
277
278 EMTElementForm emtForm(parent, this, ws);
279 emtForm.SetTitle(_("Electromagnetic Transient"));
280 emtForm.CenterOnParent();
281 if (emtForm.ShowModal() == wxID_OK) {
282 return true;
283 }
284 return false;
285}
This class manages the graphical and power elements. It is responsible for handling the user's intera...
Definition Workspace.h:105

◆ UpdateData()

void EMTElement::UpdateData ( const PropertiesData properties = nullptr,
bool  updateVoltageBase = false 
)

Definition at line 1207 of file EMTElement.cpp.

1208{
1209 if (properties != nullptr) {
1210 m_data.frequency = properties->GetSimulationPropertiesData().stabilityFrequency;
1211 m_data.atpPath = properties->GetGeneralPropertiesData().atpPath;
1212 m_data.atpWorkFolder = properties->GetGeneralPropertiesData().atpWorkFolder;
1213 m_data.pspStepSize = properties->GetSimulationPropertiesData().timeStep;
1214 }
1215 if (!m_parentList.empty()) {
1216 Bus* bus = static_cast<Bus*>(m_parentList[0]);
1217 if (bus != nullptr) {
1218 auto busData = bus->GetElectricalData();
1219 std::complex<double> voltage = std::complex<double>(1.0, 0.0);
1220 if (abs(busData.voltage) > 1e-3)
1221 m_data.puVoltage = busData.voltage;
1222 if (updateVoltageBase) {
1223 m_data.baseVoltage = GetValueFromUnit(busData.nominalVoltage, busData.nominalVoltageUnit);
1224 }
1225 }
1226 }
1227
1228}

Member Data Documentation

◆ m_data

EMTElementData EMTElement::m_data
protected

Definition at line 118 of file EMTElement.h.


The documentation for this class was generated from the following files: