Power System Platform  2026w10a-beta
Loading...
Searching...
No Matches
EMTElementForm.cpp
1#include "EMTElementForm.h"
2#include "../elements/powerElement/EMTElement.h"
3#include "../editors/ChartView.h"
4#include "../editors/Workspace.h"
5#include "../extLibs/fftw/fftw3.h"
6#include "ATPFileEditorForm.h"
7
8#include <wx/wfstream.h>
9#include <wx/datstrm.h>
10#include <wx/dir.h>
11#include <wx/process.h>
12
13EMTElementForm::EMTElementForm(wxWindow* parent, EMTElement* emtElement)
14 : EMTElementFormBase(parent), m_parent(parent), m_emtElement(emtElement)
15{
16 m_staticTextNode->SetLabel(m_staticTextNode->GetLabel() + wxT(" (3\u0278)"));
17
18 auto data = m_emtElement->GetEMTElementData();
19 m_textCtrlName->SetValue(data.name);
20 m_filePickerATPFile->SetPath(data.atpFile.GetFullPath());
21 LoadNodes(data.atpFile.GetFullPath());
22 m_choiceNodes->SetSelection(m_choiceNodes->FindString(data.atpNodeName));
23 m_textCtrlStepSize->SetValue(wxString::Format(wxT("%e"), data.stepSize));
24 m_spinCtrlCyclesToSS->SetValue(data.cyclesToSS);
25 m_textCtrlRecFreq->SetValue(wxString::Format(wxT("%d"), data.recordFrequency));
26 m_checkBoxUseFilter->SetValue(data.useMedianFilter);
27 m_spinCtrlMaxNumHarmonics->SetValue(data.numMaxHarmonics);
28 m_textCtrlHarmThreshold->SetValue(wxString::Format(wxT("%.2f"), data.harmonicsThreshold));
29
30 m_properties = static_cast<Workspace*>(parent)->GetProperties();
31
32 SetSize(DoGetBestSize());
33}
34
35EMTElementForm::~EMTElementForm()
36{
37}
38
39bool EMTElementForm::ValidateData()
40{
41 wxFileName fileName(m_filePickerATPFile->GetPath());
42 if (!fileName.IsOk()) {
43 wxMessageDialog msgDialog(m_parent, _("The ATP file doesn't exist. Insert the correct path."), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
44 msgDialog.ShowModal();
45 return false;
46 }
47 double stepSize = 0.0;
48 if (!m_textCtrlStepSize->GetValue().ToDouble(&stepSize)) {
49 wxMessageDialog msgDialog(m_parent, _("The step size must be a number."), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
50 msgDialog.ShowModal();
51 return false;
52 }
53 long recFreq = 0;
54 if (!m_textCtrlRecFreq->GetValue().ToLong(&recFreq)) {
55 wxMessageDialog msgDialog(m_parent, _("The steps to record data must be an integer number."), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
56 msgDialog.ShowModal();
57 return false;
58 }
59 if (m_choiceNodes->GetSelection() == wxNOT_FOUND) {
60 wxMessageDialog msgDialog(m_parent, _("No connection node selected."), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
61 msgDialog.ShowModal();
62 return false;
63 }
64 double harmThreshold = 0.0;
65 if (!m_textCtrlHarmThreshold->GetValue().ToDouble(&harmThreshold)) {
66 wxMessageDialog msgDialog(m_parent, _("The threshold to detect harmonics must be a number."), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
67 msgDialog.ShowModal();
68 return false;
69 }
70
71 auto data = m_emtElement->GetEMTElementData();
72 data.name = m_textCtrlName->GetValue();
73 data.atpFile = m_filePickerATPFile->GetPath();
74 data.atpNodeName = m_choiceNodes->GetString(m_choiceNodes->GetSelection());
75 data.stepSize = stepSize;
76 data.cyclesToSS = m_spinCtrlCyclesToSS->GetValue();
77 data.recordFrequency = recFreq;
78 data.useMedianFilter = m_checkBoxUseFilter->GetValue();
79 data.numMaxHarmonics = m_spinCtrlMaxNumHarmonics->GetValue();
80 data.harmonicsThreshold = harmThreshold;
81
82 m_emtElement->SetEMTElementData(data);
83
84 return true;
85}
86
87void EMTElementForm::OnCancelClick(wxCommandEvent& event)
88{
89 EndModal(wxID_CANCEL);
90}
91void EMTElementForm::OnOKClick(wxCommandEvent& event)
92{
93 if (ValidateData()) EndModal(wxID_OK);
94}
95
96void EMTElementForm::LoadNodes(wxString atpFilePath)
97{
98 wxArrayString atpFile;
99 wxTextFile file(atpFilePath);
100 if (!file.Exists()) return;
101
102 if (file.Open(atpFilePath)) {
103 atpFile.Add(file.GetFirstLine());
104 while (!file.Eof())
105 {
106 atpFile.Add(file.GetNextLine());
107 }
108 file.Close();
109 }
110 wxArrayString nodeList = m_emtElement->GetATPNodes(atpFile);
111 m_choiceNodes->Clear();
112 m_choiceNodes->Append(nodeList);
113}
114
115void EMTElementForm::OnEditATPFileClick(wxCommandEvent& event)
116{
117 wxFileName fileName(m_filePickerATPFile->GetPath());
118 if (!fileName.IsOk()) {
119 wxMessageDialog msgDialog(m_parent, _("The ATP file doesn't exist. Insert the correct path."), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
120 msgDialog.ShowModal();
121 return;
122 }
123 ATPFileEditorForm atpFileEditorForm(m_parent, m_filePickerATPFile->GetPath());
124 atpFileEditorForm.SetSize(800, 600);
125 atpFileEditorForm.ShowModal();
126}
127
128void EMTElementForm::OnTestClick(wxCommandEvent& event)
129{
130 if (ValidateData()) {
131 wxString errorMsg;
132 m_emtElement->UpdateData(m_properties);
133 if (!m_emtElement->CalculateCurrent(errorMsg, true)) {
134 wxMessageDialog msgDialog(m_parent, errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
135 msgDialog.ShowModal();
136 return;
137 }
138 std::vector<double> time, in, timeSamp, inSamp, outR, outI, outM, outP, freq;
139 auto atpData = m_emtElement->GetEMTElementData().atpData;
140 auto inFFTData = m_emtElement->GetEMTElementData().inFFTData;
141 auto outFFTData = m_emtElement->GetEMTElementData().outFFTData;
142 for (auto data : atpData) {
143 time.emplace_back(data.first);
144 in.emplace_back(data.second);
145 }
146 for (auto data : inFFTData) {
147 timeSamp.emplace_back(data.first);
148 inSamp.emplace_back(data.second);
149 }
150 for (auto data : outFFTData) {
151 outR.emplace_back(data.second.real());
152 outI.emplace_back(data.second.imag());
153 outM.emplace_back(abs(data.second));
154 outP.emplace_back(arg(data.second) * 180.0 / M_PI);
155 freq.emplace_back(data.first);
156 }
157
158
159 std::vector<double> currMag, currPha, harmOrder;
160 auto harmData = m_emtElement->GetEMTElementData().currHarmonics;
161 //auto harmOrderData = m_emtElement->GetEMTElementData().currHarmonicsOrder;
162 //for (size_t i = 0; i < harmData.size(); i++) {
163 // currMag.emplace_back(abs(harmData[i]));
164 // currPha.emplace_back(arg(harmData[i]) * 180.0 / M_PI);
165 // harmOrder.emplace_back(static_cast<double>(harmOrderData[i]));
166 //}
167 for(auto const& data : harmData){
168 currMag.emplace_back(abs(data.second));
169 currPha.emplace_back(arg(data.second) * 180.0 / M_PI);
170 harmOrder.emplace_back(static_cast<double>(data.first));
171 }
172
173 std::vector<ElementPlotData> plotDataList;
174 ElementPlotData plotATPData(_("ATP Output"), ElementPlotData::CurveType::CT_TEST);
175 ElementPlotData plotFFTData(_("Fourier Analysis"), ElementPlotData::CurveType::CT_TEST);
176 ElementPlotData plotCurrData(_("Current Phasor"), ElementPlotData::CurveType::CT_TEST);
177
178 plotATPData.AddData(in, _("Data"));
179
180 plotFFTData.AddData(inSamp, _("Input"));
181 plotFFTData.AddData(timeSamp, _("Time Sampled"));
182 plotFFTData.AddData(outR, _("Real"));
183 plotFFTData.AddData(outI, _("Imaginary"));
184 plotFFTData.AddData(outM, _("Magnitude"));
185 plotFFTData.AddData(outP, _("Phase"));
186 plotFFTData.AddData(freq, _("Frequency"));
187
188 plotCurrData.AddData(currMag, _("Magnitude"));
189 plotCurrData.AddData(currPha, _("Phase"));
190 plotCurrData.AddData(harmOrder, _("Harmonic Order"));
191
192 plotDataList.push_back(plotATPData);
193 plotDataList.push_back(plotFFTData);
194 plotDataList.push_back(plotCurrData);
195 ChartView* cView = new ChartView(this, plotDataList, time, m_properties->GetGeneralPropertiesData().plotLib);
196 cView->Show();
197 }
198}
199void EMTElementForm::OnATPFileChange(wxFileDirPickerEvent& event)
200{
201 LoadNodes(m_filePickerATPFile->GetPath());
202}
This class is responsible to manage the charts generated in the transient electromechanical studies.
Definition ChartView.h:49
Element to connect ATP-EMTP.
Definition EMTElement.h:65
This class manages the graphical and power elements. It is responsible for handling the user's intera...
Definition Workspace.h:103