Skip to content

Commit 5f9f0e6

Browse files
authored
Merge pull request #1584 from NREL/pysam_hybrids
Pysam hybrids
2 parents 54b86fd + 4ea27ba commit 5f9f0e6

File tree

752 files changed

+1318918
-29953
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

752 files changed

+1318918
-29953
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ jobs:
6767
run: |
6868
echo "GITHUB_REPOSITORY_OWNER=${GITHUB_REPOSITORY_OWNER}" >> $GITHUB_ENV
6969
git ls-remote --heads --exit-code https://github.com/${GITHUB_REPOSITORY_OWNER}/lk.git $GIT_BRANCH
70-
if [[ $? != "0" ]]; then echo "LK_BRANCH=patch" >> $GITHUB_ENV; else echo "LK_BRANCH=$GIT_BRANCH" >> $GITHUB_ENV; fi
70+
if [[ $? != "0" ]]; then echo "LK_BRANCH=develop" >> $GITHUB_ENV; else echo "LK_BRANCH=$GIT_BRANCH" >> $GITHUB_ENV; fi
7171
git ls-remote --heads --exit-code https://github.com/${GITHUB_REPOSITORY_OWNER}/wex.git $GIT_BRANCH
72-
if [[ $? != "0" ]]; then echo "WEX_BRANCH=patch" >> $GITHUB_ENV; else echo "WEX_BRANCH=$GIT_BRANCH" >> $GITHUB_ENV; fi
72+
if [[ $? != "0" ]]; then echo "WEX_BRANCH=develop" >> $GITHUB_ENV; else echo "WEX_BRANCH=$GIT_BRANCH" >> $GITHUB_ENV; fi
7373
git ls-remote --heads --exit-code https://github.com/${GITHUB_REPOSITORY_OWNER}/ssc.git $GIT_BRANCH
74-
if [[ $? != "0" ]]; then echo "SSC_BRANCH=patch" >> $GITHUB_ENV; else echo "SSC_BRANCH=$GIT_BRANCH" >> $GITHUB_ENV; fi
74+
if [[ $? != "0" ]]; then echo "SSC_BRANCH=develop" >> $GITHUB_ENV; else echo "SSC_BRANCH=$GIT_BRANCH" >> $GITHUB_ENV; fi
7575
7676
- name: Install wxWidgets
7777
run: |
@@ -211,11 +211,11 @@ jobs:
211211
run: |
212212
echo "GITHUB_REPOSITORY_OWNER=${GITHUB_REPOSITORY_OWNER}" >> $GITHUB_ENV
213213
git ls-remote --heads --exit-code https://github.com/${GITHUB_REPOSITORY_OWNER}/lk.git $GIT_BRANCH
214-
if [[ $? != "0" ]]; then echo "LK_BRANCH=patch" >> $GITHUB_ENV; else echo "LK_BRANCH=$GIT_BRANCH" >> $GITHUB_ENV; fi
214+
if [[ $? != "0" ]]; then echo "LK_BRANCH=develop" >> $GITHUB_ENV; else echo "LK_BRANCH=$GIT_BRANCH" >> $GITHUB_ENV; fi
215215
git ls-remote --heads --exit-code https://github.com/${GITHUB_REPOSITORY_OWNER}/wex.git $GIT_BRANCH
216-
if [[ $? != "0" ]]; then echo "WEX_BRANCH=patch" >> $GITHUB_ENV; else echo "WEX_BRANCH=$GIT_BRANCH" >> $GITHUB_ENV; fi
216+
if [[ $? != "0" ]]; then echo "WEX_BRANCH=develop" >> $GITHUB_ENV; else echo "WEX_BRANCH=$GIT_BRANCH" >> $GITHUB_ENV; fi
217217
git ls-remote --heads --exit-code https://github.com/${GITHUB_REPOSITORY_OWNER}/ssc.git $GIT_BRANCH
218-
if [[ $? != "0" ]]; then echo "SSC_BRANCH=patch" >> $GITHUB_ENV; else echo "SSC_BRANCH=$GIT_BRANCH" >> $GITHUB_ENV; fi
218+
if [[ $? != "0" ]]; then echo "SSC_BRANCH=develop" >> $GITHUB_ENV; else echo "SSC_BRANCH=$GIT_BRANCH" >> $GITHUB_ENV; fi
219219
220220
- name: Install wxWidgets
221221
run: |

api/api_autogen/builder_C_API.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2929
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3030
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3131
*/
32-
33-
32+
// C++17 only - not in patch branch
33+
//#include <filesystem>
34+
#include <wx/file.h>
3435
#include <shared/lib_util.h>
3536

3637
#include "builder_C_API.h"
@@ -39,8 +40,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3940
void builder_C_API::create_SAM_headers(const std::string &cmod, const std::string &file_dir, bool stateful) {
4041
std::string cmod_symbol = format_as_symbol(cmod);
4142

43+
if (cmod_symbol == "6parsolve")
44+
cmod_symbol = "SixParsolve";
45+
else if (cmod_symbol == "Tcsmslf")
46+
cmod_symbol = "TcsMSLF";
47+
else if (root->m_vardefs.find(cmod_symbol) != root->m_vardefs.end())
48+
cmod_symbol += "Model";
49+
50+
std::string filename = file_dir + "/SAM_" + cmod_symbol + ".h";
51+
// if (std::filesystem::exists(filename))
52+
if (wxFileExists(filename))
53+
return;
54+
4255
std::ofstream fx_file;
43-
fx_file.open(file_dir + "/SAM_" + cmod_symbol + ".h");
56+
fx_file.open(filename);
4457
assert(fx_file.is_open());
4558

4659
fx_file << "#ifndef SAM_" << util::upper_case(cmod_symbol)<< "_H_\n"
@@ -193,8 +206,20 @@ void builder_C_API::create_SAM_headers(const std::string &cmod, const std::strin
193206
void builder_C_API::create_SAM_definitions(const std::string &cmod, const std::string &file_dir, bool stateful) {
194207
std::string cmod_symbol = format_as_symbol(cmod);
195208

209+
if (cmod_symbol == "6parsolve")
210+
cmod_symbol = "SixParsolve";
211+
else if (cmod_symbol == "Tcsmslf")
212+
cmod_symbol = "TcsMSLF";
213+
else if (root->m_vardefs.find(cmod_symbol) != root->m_vardefs.end())
214+
cmod_symbol += "Model";
215+
216+
std::string filename = file_dir + "/SAM_" + cmod_symbol + ".cpp";
217+
// if (std::filesystem::exists(filename))
218+
if (wxFileExists(filename))
219+
return;
220+
196221
std::ofstream fx_file;
197-
fx_file.open(file_dir + "/SAM_" + cmod_symbol + ".cpp");
222+
fx_file.open(filename);
198223
assert(fx_file.is_open());
199224

200225
fx_file << "#include <string>\n"
@@ -228,6 +253,7 @@ void builder_C_API::create_SAM_definitions(const std::string &cmod, const std::s
228253

229254
if (mm->first == "AdjustmentFactors")
230255
continue;
256+
231257

232258
for (auto & vardef : vardefs) {
233259
std::string var_symbol = vardef.first;
@@ -335,8 +361,6 @@ void builder_C_API::create_SAM_definitions(const std::string &cmod, const std::s
335361
else{
336362
throw std::runtime_error(vd.type + " for " + var_name);
337363
}
338-
fx_file << "\n\n";
339-
340364
}
341365
}
342366
fx_file.close();

api/api_autogen/builder_PySAM.cpp

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -173,19 +173,21 @@ void builder_PySAM::all_options_of_cmod(const std::string &cmod) {
173173
void builder_PySAM::create_PySAM_files(const std::string &cmod, const std::string &file_dir, bool stateful) {
174174
std::string cmod_symbol = format_as_symbol(cmod);
175175

176-
std::string tech_symbol = cmod_symbol;
177176
if (cmod_symbol == "6parsolve")
178-
tech_symbol = "SixParsolve";
177+
cmod_symbol = "SixParsolve";
178+
else if (cmod_symbol == "Tcsmslf")
179+
cmod_symbol = "TcsMSLF";
179180
else if (root->m_vardefs.find(cmod_symbol) != root->m_vardefs.end())
180-
tech_symbol += "Model";
181+
cmod_symbol += "Model";
182+
std::string tech_symbol = cmod_symbol;
181183

182184
std::ofstream fx_file;
183185
fx_file.open(file_dir + "/modules/" + tech_symbol + ".c");
184186
assert(fx_file.is_open());
185187

186188
fx_file << "#include <Python.h>\n"
187189
"\n"
188-
"#include <SAM_" << cmod_symbol << ".h>\n"
190+
"#include <SAM_" << tech_symbol << ".h>\n"
189191
"#include <SAM_api.h>\n"
190192
"\n"
191193
"#include \"PySAM_utils.h\"\n\n";
@@ -612,6 +614,30 @@ void builder_PySAM::create_PySAM_files(const std::string &cmod, const std::strin
612614

613615
fx_file << "\tPyObject_Del(self);\n"
614616
"}\n\n\n";
617+
fx_file << "static PyObject *\n"
618+
"" << tech_symbol << "_get_data_ptr(" << object_type << " *self, PyObject *args)\n"
619+
"{\n\tPyObject* ptr = PyLong_FromVoidPtr((void*)self->data_ptr);\n"
620+
"\treturn ptr;\n}\n\n\n";
621+
622+
fx_file << "static PyObject *\n"
623+
"" << tech_symbol << "_set_data_ptr(" << object_type << " *self, PyObject *args)\n"
624+
"{\n"
625+
"\tlong long int ptr = 0; // 64 bit arch\n"
626+
"\tif (!PyArg_ParseTuple(args, \"L:data_ptr\", &ptr)){\n"
627+
"\t\tPyErr_BadArgument();\n"
628+
"\t\treturn NULL;\n"
629+
"\t}\n\tself->data_ptr = (void*)ptr;\n";
630+
631+
// modify the data ptr for all the groups
632+
for (auto& i : root->vardefs_order) {
633+
auto mm = root->m_vardefs.find(i);
634+
if (mm->second.empty()) continue;
635+
std::string module_symbol = format_as_symbol(mm->first);
636+
fx_file << "\tVarGroupObject* " << module_symbol << "_obj = (VarGroupObject*)PyDict_GetItemString(self->x_attr, \"" << module_symbol << "\");\n"
637+
"\t" << module_symbol << "_obj->data_ptr = (void*)ptr;\n";
638+
}
639+
640+
fx_file << "\treturn Py_None;\n}\n\n\n";
615641

616642
if (stateful) {
617643
fx_file << "static PyObject *\n"
@@ -693,6 +719,10 @@ void builder_PySAM::create_PySAM_files(const std::string &cmod, const std::strin
693719

694720
fx_file << "\t\t{\"execute\", (PyCFunction)" << tech_symbol << "_execute, METH_VARARGS,\n"
695721
"\t\t\t\tPyDoc_STR(\"execute(int verbosity) -> None\\n Execute simulation with verbosity level 0 (default) or 1\")},\n"
722+
"\t\t{\"get_data_ptr\", (PyCFunction)" << tech_symbol << "_get_data_ptr, METH_VARARGS,\n"
723+
"\t\t\t\tPyDoc_STR(\"get_data_ptr() -> Pointer\\n Get ssc_data_t pointer\")},\n"
724+
"\t\t{\"set_data_ptr\", (PyCFunction)" << tech_symbol << "_set_data_ptr, METH_VARARGS,\n"
725+
"\t\t\t\tPyDoc_STR(\"set_data_ptr(data_ptr)\\n Set ssc_data_t pointer\")},\n"
696726
"\t\t{\"assign\", (PyCFunction)" << tech_symbol << "_assign, METH_VARARGS,\n"
697727
"\t\t\t\tPyDoc_STR(\"assign(dict) -> None\\n Assign attributes from nested dictionary, except for Outputs\\n\\n"
698728
"``nested_dict = { '" << root->vardefs_order[0] << "': { var: val, ...}, ...}``\")},\n"
@@ -1100,8 +1130,17 @@ void builder_PySAM::create_PySAM_files(const std::string &cmod, const std::strin
11001130
fx_file << "-";
11011131
fx_file << "-\n\n";
11021132

1103-
fx_file << ".. autoclass:: PySAM." << tech_symbol << "." << tech_symbol << "." << module_symbol << "\n";
1104-
fx_file << "\t:members:\n\n";
1133+
if (module_symbol == "AdjustmentFactors") {
1134+
fx_file << ".. autoclass:: PySAM.AdjustmentFactors.AdjustmentFactors\n";
1135+
}
1136+
else {
1137+
fx_file << ".. autoclass:: PySAM." << tech_symbol << "." << tech_symbol << "." << module_symbol << "\n";
1138+
}
1139+
fx_file << "\t:members:\n";
1140+
if (module_symbol == "AdjustmentFactors") {
1141+
fx_file << "\t:noindex:\n";
1142+
}
1143+
fx_file << "\n";
11051144
}
11061145

11071146
fx_file.close();
@@ -1127,6 +1166,12 @@ void builder_PySAM::create_PySAM_files(const std::string &cmod, const std::strin
11271166
"\tdef export(self):\n"
11281167
"\t\tpass\n"
11291168
"\n"
1169+
"\tdef get_data_ptr(self):\n"
1170+
"\t\tpass\n"
1171+
"\n"
1172+
"\tdef set_data_ptr(self, data_ptr):\n"
1173+
"\t\tpass\n"
1174+
"\n"
11301175
"\tdef __getattribute__(self, *args, **kwargs):\n"
11311176
"\t\tpass\n"
11321177
"\n"
@@ -1159,14 +1204,26 @@ void builder_PySAM::create_PySAM_files(const std::string &cmod, const std::strin
11591204
"\t\t\tpass\n"
11601205
"\t\n"
11611206
"\t\tconstant = float\n"
1207+
"\t\ten_hourly = float\n"
1208+
"\t\ten_periods = float\n"
1209+
"\t\ten_timeindex = float\n"
1210+
"\t\thourly = tuple\n"
1211+
"\t\tperiods = tuple\n"
1212+
"\t\timeindex = tuple\n"
11621213
"\t\tdc_constant = float\n"
1214+
"\t\tdc_en_hourly = float\n"
1215+
"\t\tdc_en_periods = float\n"
1216+
"\t\tdc_en_timeindex = float\n"
11631217
"\t\tdc_hourly = tuple\n"
11641218
"\t\tdc_periods = tuple\n"
1165-
"\t\thourly = tuple\n"
1166-
"\t\tperiods = tuple\n"
1219+
"\t\tdc_imeindex = tuple\n"
11671220
"\t\tsf_constant = float\n"
1221+
"\t\tsf_en_hourly = float\n"
1222+
"\t\tsf_en_periods = float\n"
1223+
"\t\tsf_en_timeindex = float\n"
11681224
"\t\tsf_hourly = tuple\n"
1169-
"\t\tsf_periods = tuple\n\n";
1225+
"\t\tsf_periods = tuple\n"
1226+
"\t\tsf_timeindex = tuple\n\n";
11701227
continue;
11711228
}
11721229

api/api_autogen/builder_generator.cpp

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4141
#include <shared/lib_util.h>
4242
#include <ssc/sscapi.h>
4343
#include <ssc/ssc_equations.h>
44+
#include <ssc/core.h>
4445

4546
#include "lk_env.h"
4647
#include "lk_eval.h"
@@ -54,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5455
#include "builder_C_API.h"
5556
#include "builder_PySAM.h"
5657

58+
5759
std::unordered_map<std::string, bool> SAM_completed_cmods;
5860

5961

@@ -80,8 +82,11 @@ builder_generator::builder_generator(config_extractor *ce){
8082
for (size_t i = 0; i < cmods.size(); i++){
8183
std::string cmod_name = cmods[i];
8284
ssc_module_t p_mod = ssc_module_create(const_cast<char*>(cmod_name.c_str()));
83-
ssc_module_objects.insert({cmod_name, p_mod});
8485

86+
if (config_name.find("Hybrid") != std::string::npos) {
87+
ssc_module_hybridize(p_mod);
88+
}
89+
ssc_module_objects.insert({cmod_name, p_mod});
8590
}
8691
}
8792

@@ -123,12 +128,18 @@ void builder_generator::select_ui_variables(std::string ui_name, std::map<std::s
123128
void builder_generator::gather_variables_ssc(const std::string &cmod_name) {
124129
ssc_module_t p_mod = ssc_module_create(const_cast<char*>(cmod_name.c_str()));
125130

131+
// hybrid technology compute modules have extra financial variables that need to be exported to defaults
132+
if (active_config.find("Hybrid") != std::string::npos) {
133+
ssc_module_hybridize(p_mod);
134+
}
135+
126136
digraph* graph = nullptr;
127137
if (SAM_config_to_variable_graph.find(active_config) != SAM_config_to_variable_graph.end())
128138
graph = SAM_config_to_variable_graph[active_config];
129139

130140
int var_index = 0;
131141
ssc_info_t mod_info = ssc_module_var_info(p_mod, var_index);
142+
var_info* mod_info_cast = static_cast<var_info*>(mod_info);
132143
std::map<std::string, var_def> adj_map;
133144
std::map<std::string, var_def> outputs_map;
134145
while (mod_info){
@@ -173,17 +184,6 @@ void builder_generator::gather_variables_ssc(const std::string &cmod_name) {
173184
std::vector<std::string> ssctype_str = {"invalid", "string", "number", "array", "matrix", "table"};
174185
vd.type_n = ssc_info_data_type(mod_info);
175186
vd.type = ssctype_str[vd.type_n];
176-
/*
177-
if (vd.group == "Adjustment Factors") {
178-
size_t pos = vd.name.find(':');
179-
size_t pos2 = vd.name.find("adjust");
180-
vd.name = vd.name.substr(0, pos2) + vd.name.substr(pos+1);
181-
adj_map.insert({vd.name, vd});
182-
++var_index;
183-
mod_info = ssc_module_var_info(p_mod, var_index);
184-
continue;
185-
}
186-
*/
187187
int var_type = ssc_info_var_type(mod_info);
188188

189189
size_t pos = vd.name.find(':');
@@ -419,32 +419,31 @@ void builder_generator::export_variables_json(const std::string &cmod, const std
419419

420420
VarValue* vv = nullptr;
421421

422-
/* // if adjustment factors, the default values are stored in a table
423-
if (module_name == "AdjustmentFactors"){
422+
// if adjustment factors, the variables need to have the 'adjust_' prefix removed
423+
if (module_symbol == "AdjustmentFactors"){
424424
size_t pos = v.name.find('_');
425-
std::string adj_type = "adjust";
426-
if (pos != std::string::npos){
427-
adj_type = v.name.substr(0, pos + 1) + adj_type;
428-
}
429-
430-
vv = SAM_config_to_defaults[config_name][adj_type];
425+
vv = SAM_config_to_defaults[config_name][v.name];
431426
if (vv){
432-
std::string name = v.name.substr(pos+1);
433-
if (name == "hourly" && !(vv->Table().Get("en_hourly")->Boolean()))
434-
continue;
435-
if (name == "periods" && !(vv->Table().Get("en_periods")->Boolean()))
436-
continue;
437-
vv = vv->Table().Get(name);
427+
var_symbol = v.name.substr(pos+1);
438428
}
439429
else
440430
continue;
441431
}
442-
else
443-
*/ vv = SAM_config_to_defaults[config_name][v.name];
432+
else{
433+
if (config_name.find("Hybrid") != std::string::npos){
434+
VarValue* vt = SAM_config_to_defaults[config_name].Get(format_as_symbol(cmod));
435+
if (!vt)
436+
vt = SAM_config_to_defaults[config_name].Get("Hybrid");
437+
vv = vt->Table()[v.name];
438+
}
439+
else{
440+
vv = SAM_config_to_defaults[config_name][v.name];
444441

445-
// if it's a battery configuration, turn on battery by default
446-
if ((cmod == "battery" && v.name == "en_batt") || (cmod == "battwatts" && v.name == "batt_simple_enable"))
447-
vv->Set(1);
442+
// if it's a battery configuration, turn on battery by default. Hybrid techs don't need this because cmod_hybrid does it
443+
if ((cmod == "battery" && v.name == "en_batt") || (cmod == "battwatts" && v.name == "batt_simple_enable"))
444+
vv->Set(1);
445+
}
446+
}
448447

449448
// vv can be null in the case of variables not available in UI
450449
if (!vv && v.reqif != "*")
@@ -458,7 +457,6 @@ void builder_generator::export_variables_json(const std::string &cmod, const std
458457
json << "\n\t\t\t\"" + format_as_variable(var_symbol) + "\": ";
459458
json << ssc_value_to_json(v.type_n, vv);
460459

461-
462460
first = false;
463461
}
464462
json << "\n\t\t}";

api/api_autogen/builder_generator_helper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ std::string ssc_value_to_json(int ssc_type, VarValue* vv){
211211
break;
212212
case SSC_ARRAY:
213213
json += "[";
214-
if (vv){
214+
if (vv && vv->Array().size()){
215215
std::vector<double> vec = vv->Array();
216216
for (size_t j = 0; j < vec.size(); j++){
217217
if (vec[j] > std::numeric_limits<double>::max()){

0 commit comments

Comments
 (0)