KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
sim_lib_mgr.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2022 Mikolaj Wielgus
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * https://www.gnu.org/licenses/gpl-3.0.html
20 * or you may search the http://www.gnu.org website for the version 3 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <filename_resolver.h>
26#include <pgm_base.h>
27#include <string>
28#include <string_utils.h>
29#include <common.h>
30#include <functional>
31#include <sch_symbol.h>
32#include <schematic.h>
33
34// Include simulator headers after wxWidgets headers to avoid conflicts with Windows headers
35// (especially on msys2 + wxWidgets 3.0.x)
36#include <sim/sim_lib_mgr.h>
37#include <sim/sim_library.h>
38#include <sim/sim_model.h>
39#include <sim/sim_model_ideal.h>
40
41using namespace std::placeholders;
42
43
45 m_files( aFiles ),
46 m_project( aPrj ),
47 m_forceFullParse( false )
48{
49}
50
51
53{
54 m_libraries.clear();
55 m_models.clear();
56}
57
58
59wxString SIM_LIB_MGR::ResolveLibraryPath( const wxString& aLibraryPath, REPORTER& aReporter )
60{
62
64
65 wxString expandedPath = resolver.ResolvePath( aLibraryPath, wxEmptyString, m_files );
66
67 wxFileName fn( expandedPath );
68
69 if( fn.IsAbsolute() )
70 return fn.GetFullPath();
71
72 wxFileName projectFn( m_project ? m_project->AbsolutePath( expandedPath ) : expandedPath );
73
74 if( projectFn.Exists() )
75 return projectFn.GetFullPath();
76
77 wxFileName spiceLibFn( expandedPath );
78 wxString spiceLibDir;
79
80 wxGetEnv( wxT( "SPICE_LIB_DIR" ), &spiceLibDir );
81
82 if( !spiceLibDir.IsEmpty() && spiceLibFn.MakeAbsolute( spiceLibDir ) && spiceLibFn.Exists() )
83 return spiceLibFn.GetFullPath();
84
85 if( spiceLibDir.IsEmpty() || spiceLibFn.GetFullPath() == projectFn.GetFullPath() )
86 {
87 aReporter.Report( wxString::Format( _( "Simulation model library not found at '%s'" ),
88 projectFn.GetFullPath() ) );
89 }
90 else
91 {
92 aReporter.Report( wxString::Format( _( "Simulation model library not found at '%s' or '%s'" ),
93 projectFn.GetFullPath(),
94 spiceLibFn.GetFullPath() ) );
95 }
96
97 return aLibraryPath;
98}
99
100
101wxString SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const wxString& aLibPath,
102 const wxString& aRelativeLib,
103 REPORTER& aReporter )
104{
105 wxFileName testPath( aLibPath );
106 wxString fullPath( aLibPath );
107
108 if( !testPath.IsAbsolute() && !aRelativeLib.empty() )
109 {
110 wxString relLib( aRelativeLib );
111
112 relLib = ResolveLibraryPath( relLib, aReporter );
113
114 wxFileName fn( relLib );
115
116 testPath.MakeAbsolute( fn.GetPath( true ) );
117 fullPath = testPath.GetFullPath();
118 }
119
120 wxFileName fn( fullPath );
121
122 if( !fn.Exists() )
123 fullPath = aLibPath;
124
125 fullPath = ResolveLibraryPath( fullPath, aReporter );
126
127 return fullPath;
128}
129
130
131void SIM_LIB_MGR::SetLibrary( const wxString& aLibraryPath, REPORTER& aReporter )
132{
133 wxString path = ResolveLibraryPath( aLibraryPath, aReporter );
134
136 return;
137
138 if( !wxFileName::Exists( path ) )
139 {
140 aReporter.Report( wxString::Format( _( "Simulation model library not found at '%s'" ),
141 path ) );
142 return;
143 }
144
145 std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( path, m_forceFullParse, aReporter,
146 [&]( const wxString& libPath, const wxString& relativeLib ) -> wxString
147 {
148 return ResolveEmbeddedLibraryPath( libPath, relativeLib, aReporter );
149 } );
150
151 Clear();
152 m_libraries[path] = std::move( library );
153}
154
155
156SIM_MODEL& SIM_LIB_MGR::CreateModel( SIM_MODEL::TYPE aType, const std::vector<SCH_PIN*>& aPins,
157 REPORTER& aReporter )
158{
159 m_models.push_back( SIM_MODEL::Create( aType, aPins, aReporter ) );
160 return *m_models.back();
161}
162
163
165 const std::vector<SCH_PIN*>& aPins, REPORTER& aReporter )
166{
167 m_models.push_back( SIM_MODEL::Create( aBaseModel, aPins, aReporter ) );
168 return *m_models.back();
169}
170
171
173 const std::vector<SCH_PIN*>& aPins,
174 const std::vector<SCH_FIELD>& aFields, REPORTER& aReporter )
175{
176 m_models.push_back( SIM_MODEL::Create( aBaseModel, aPins, aFields, aReporter ) );
177 return *m_models.back();
178}
179
181 REPORTER& aReporter )
182{
183 // Note: currently this creates a resolved model (all Kicad variables references are resolved
184 // before building the model).
185 //
186 // That's not what we want if this is ever called from the Simulation Model Editor (or other
187 // editors, but it is what we want if called to generate a netlist or other exported items.
188
189
190 std::vector<SCH_FIELD> fields;
191
192 for( const SCH_FIELD& field : aSymbol.GetFields() )
193 {
194 if( field.GetId() == FIELD_T::REFERENCE )
195 {
196 fields.emplace_back( VECTOR2I(), FIELD_T::USER, &aSymbol, field.GetName() );
197 fields.back().SetText( aSymbol.GetRef( aSheetPath ) );
198 }
199 else if( field.GetId() == FIELD_T::VALUE || field.GetName().StartsWith( wxS( "Sim." ) ) )
200 {
201 fields.emplace_back( VECTOR2I(), FIELD_T::USER, &aSymbol, field.GetName() );
202 fields.back().SetText( field.GetShownText( aSheetPath, false ) );
203 }
204 }
205
206 auto getOrCreateField =
207 [&aSymbol, &fields]( const wxString& name ) -> SCH_FIELD*
208 {
209 for( SCH_FIELD& field : fields )
210 {
211 if( field.GetName().IsSameAs( name ) )
212 return &field;
213 }
214
215 fields.emplace_back( &aSymbol, FIELD_T::USER, name );
216 return &fields.back();
217 };
218
219 wxString deviceType;
220 wxString modelType;
221 wxString modelParams;
222 wxString pinMap;
223 bool storeInValue = false;
224
225 // Infer RLC and VI models if they aren't specified
227 &deviceType, &modelType, &modelParams, &pinMap ) )
228 {
229 getOrCreateField( SIM_DEVICE_FIELD )->SetText( deviceType );
230
231 if( !modelType.IsEmpty() )
232 getOrCreateField( SIM_DEVICE_SUBTYPE_FIELD )->SetText( modelType );
233
234 getOrCreateField( SIM_PARAMS_FIELD )->SetText( modelParams );
235 getOrCreateField( SIM_PINS_FIELD )->SetText( pinMap );
236
237 storeInValue = true;
238 }
239
240 std::vector<SCH_PIN*> sourcePins = aSymbol.GetAllLibPins();
241
242 std::sort( sourcePins.begin(), sourcePins.end(),
243 []( const SCH_PIN* lhs, const SCH_PIN* rhs )
244 {
245 return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0;
246 } );
247
248 SIM_LIBRARY::MODEL model = CreateModel( fields, sourcePins, true, aReporter );
249
250 model.model.SetIsStoredInValue( storeInValue );
251
252 return model;
253}
254
255
256SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector<SCH_FIELD>& aFields,
257 const std::vector<SCH_PIN*>& aPins, bool aResolved,
258 REPORTER& aReporter )
259{
260 std::string libraryPath = GetFieldValue( &aFields, SIM_LIBRARY::LIBRARY_FIELD );
261 std::string baseModelName = GetFieldValue( &aFields, SIM_LIBRARY::NAME_FIELD );
262
263 if( libraryPath != "" )
264 {
265 return CreateModel( libraryPath, baseModelName, aFields, aPins, aReporter );
266 }
267 else
268 {
269 m_models.push_back( SIM_MODEL::Create( aFields, aPins, aResolved, aReporter ) );
270 return { baseModelName, *m_models.back() };
271 }
272}
273
274
275SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath,
276 const std::string& aBaseModelName,
277 const std::vector<SCH_FIELD>& aFields,
278 const std::vector<SCH_PIN*>& aPins,
279 REPORTER& aReporter )
280{
281 wxString msg;
282 SIM_LIBRARY* library = nullptr;
283 SIM_MODEL* baseModel = nullptr;
284 std::string modelName;
285 wxString path = ResolveLibraryPath( aLibraryPath, aReporter );
286
287 auto it = m_libraries.find( path );
288
289 if( it == m_libraries.end() )
290 {
291 it = m_libraries.emplace( path, SIM_LIBRARY::Create( path, m_forceFullParse, aReporter,
292 [&]( const wxString& libPath, const wxString& relativeLib ) -> wxString
293 {
294 return ResolveEmbeddedLibraryPath( libPath, relativeLib, aReporter );
295 } ) ).first;
296 }
297
298 library = &*it->second;
299
300 if( aBaseModelName == "" )
301 {
302 msg.Printf( _( "Error loading simulation model: no '%s' field" ),
304
305 aReporter.Report( msg, RPT_SEVERITY_ERROR );
306
307 modelName = _( "unknown" ).ToStdString();
308 }
309 else if( library )
310 {
311 baseModel = library->FindModel( aBaseModelName );
312 modelName = aBaseModelName;
313
314 if( !baseModel )
315 {
316 msg.Printf( _( "Error loading simulation model: could not find base model '%s' "
317 "in library '%s'" ),
318 aBaseModelName,
319 path );
320
321 aReporter.Report( msg, RPT_SEVERITY_ERROR );
322 }
323 }
324
325 m_models.push_back( SIM_MODEL::Create( baseModel, aPins, aFields, aReporter ) );
326
327 return { modelName, *m_models.back() };
328}
329
330
331void SIM_LIB_MGR::SetModel( int aIndex, std::unique_ptr<SIM_MODEL> aModel )
332{
333 m_models.at( aIndex ) = std::move( aModel );
334}
335
336
337std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>> SIM_LIB_MGR::GetLibraries() const
338{
339 std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>> libraries;
340
341 for( auto& [path, library] : m_libraries )
342 libraries.try_emplace( path, *library );
343
344 return libraries;
345}
346
347
348std::vector<std::reference_wrapper<SIM_MODEL>> SIM_LIB_MGR::GetModels() const
349{
350 std::vector<std::reference_wrapper<SIM_MODEL>> models;
351
352 for( const std::unique_ptr<SIM_MODEL>& model : m_models )
353 models.emplace_back( *model );
354
355 return models;
356}
const char * name
Definition: DXF_plotter.cpp:59
Provide an extensible class to resolve 3D model paths.
wxString ResolvePath(const wxString &aFileName, const wxString &aWorkingPath, const EMBEDDED_FILES *aFiles)
Determine the full path of the given file name.
bool SetProject(const PROJECT *aProject, bool *flgChanged=nullptr)
Set the current KiCad project directory as the first entry in the model path list.
Container for project specific data.
Definition: project.h:64
virtual const wxString AbsolutePath(const wxString &aFileName) const
Fix up aFileName if it is relative to the project's directory to be an absolute path and filename.
Definition: project.cpp:370
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:73
virtual bool HasMessageOfSeverity(int aSeverityMask) const
Returns true if the reporter has one or more messages matching the specified severity mask.
Definition: reporter.cpp:56
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
void SetText(const wxString &aText) override
Definition: sch_field.cpp:1069
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Schematic symbol object.
Definition: sch_symbol.h:75
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
Definition: sch_symbol.cpp:841
std::vector< SCH_PIN * > GetAllLibPins() const
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
Definition: sch_symbol.cpp:611
static std::unique_ptr< SIM_LIBRARY > Create(const wxString &aFilePath, bool aForceFullParse, REPORTER &aReporter, const std::function< wxString(const wxString &, const wxString &)> &aResolver)
Read library from a source file (e.g.
Definition: sim_library.cpp:34
static constexpr auto LIBRARY_FIELD
Definition: sim_library.h:35
static constexpr auto NAME_FIELD
Definition: sim_library.h:36
void SetModel(int aIndex, std::unique_ptr< SIM_MODEL > aModel)
wxString ResolveLibraryPath(const wxString &aLibraryPath, REPORTER &aReporter)
Definition: sim_lib_mgr.cpp:59
const PROJECT * m_project
Definition: sim_lib_mgr.h:87
EMBEDDED_FILES * m_files
Definition: sim_lib_mgr.h:86
bool m_forceFullParse
Definition: sim_lib_mgr.h:88
SIM_MODEL & CreateModel(SIM_MODEL::TYPE aType, const std::vector< SCH_PIN * > &aPins, REPORTER &aReporter)
std::vector< std::unique_ptr< SIM_MODEL > > m_models
Definition: sim_lib_mgr.h:90
SIM_LIB_MGR(const PROJECT *aPrj, EMBEDDED_FILES *aFiles)
Definition: sim_lib_mgr.cpp:44
std::map< wxString, std::reference_wrapper< const SIM_LIBRARY > > GetLibraries() const
wxString ResolveEmbeddedLibraryPath(const wxString &aLibPath, const wxString &aRelativeLib, REPORTER &aReporter)
std::vector< std::reference_wrapper< SIM_MODEL > > GetModels() const
void Clear()
Definition: sim_lib_mgr.cpp:52
void SetLibrary(const wxString &aLibraryPath, REPORTER &aReporter)
std::map< wxString, std::unique_ptr< SIM_LIBRARY > > m_libraries
Definition: sim_lib_mgr.h:89
static bool InferSimModel(T &aSymbol, std::vector< SCH_FIELD > *aFields, bool aResolve, SIM_VALUE_GRAMMAR::NOTATION aNotation, wxString *aDeviceType, wxString *aModelType, wxString *aModelParams, wxString *aPinMap)
Definition: sim_model.cpp:1019
static std::unique_ptr< SIM_MODEL > Create(TYPE aType, const std::vector< SCH_PIN * > &aPins, REPORTER &aReporter)
Definition: sim_model.cpp:481
void SetIsStoredInValue(bool aIsStoredInValue)
Definition: sim_model.h:497
The common library.
#define _(s)
static FILENAME_RESOLVER * resolver
Definition: export_idf.cpp:53
see class PGM_BASE
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_UNDEFINED
wxString GetFieldValue(const std::vector< SCH_FIELD > *aFields, FIELD_T aFieldType)
Definition: sch_field.h:406
#define SIM_PINS_FIELD
Definition: sim_model.h:54
#define SIM_DEVICE_FIELD
Definition: sim_model.h:52
#define SIM_PARAMS_FIELD
Definition: sim_model.h:55
#define SIM_DEVICE_SUBTYPE_FIELD
Definition: sim_model.h:53
SIM_MODEL & model
Definition: sim_library.h:41
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695