diff --git a/src/demand.c b/src/demand.c index b97ee86..7b8a0b1 100644 --- a/src/demand.c +++ b/src/demand.c @@ -32,6 +32,24 @@ typedef struct demand_data_s } demand_data_t; + +list_t *create_demand_list(double base_demand, int pattern_index, char *category_name) +{ + list_t *demand_list; + demand_data_t *demand_data; + + demand_list = create_list(get_demand_data_size(), delete_demand_data); + if (!demand_list) return NULL; + + demand_data = create_demand_data(base_demand, pattern_index, category_name); + if (!demand_data) return NULL; + + append_list(demand_list, &demand_data); + + return demand_list; +} + + demand_data_t *create_demand_data(double base_demand, int pattern_index, char *category_name) { demand_data_t *demand_data = (demand_data_t *)malloc(sizeof(demand_data_t)); diff --git a/src/demand.h b/src/demand.h index 9ae0e58..fcc7826 100644 --- a/src/demand.h +++ b/src/demand.h @@ -29,6 +29,9 @@ typedef struct demand_data_s demand_data_t; // demand list gets declared in types.h struct Snode +list_t *create_demand_list(double base_demand, int pattern_index, char *category_name); + + demand_data_t *create_demand_data(double base_demand, int pat_index, char *cat_name); void delete_demand_data(void *data); diff --git a/src/epanet.c b/src/epanet.c index 0ab9ffc..407a5ff 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -2818,13 +2818,22 @@ int DLLEXPORT EN_setbasedemand(EN_Project p, int nodeIndex, int demandIndex, // Set baseline demand for specified category if (nodeIndex <= p->network.Njuncs) { - // Locate demand category record and assign demandName to it list_t *dlist = p->network.Node[nodeIndex].D; - list_node_t *lnode = get_nth_list(dlist, demandIndex); - if (!lnode) - return 253; - else - set_base_demand(lnode, baseDemand / p->Ucf[FLOW]); + // If demand list is null create one and set demand + if (!dlist) { + dlist = create_demand_list(baseDemand / p->Ucf[FLOW], 0, NULL); + if (!dlist) return 101; + + p->network.Node[nodeIndex].D = dlist; + } + // else find the demand entry and set demand + else { + list_node_t *lnode = get_nth_list(dlist, demandIndex); + if (!lnode) + return 253; + else + set_base_demand(lnode, baseDemand / p->Ucf[FLOW]); + } } return 0; } @@ -2895,12 +2904,19 @@ int DLLEXPORT EN_setdemandname(EN_Project p, int nodeIndex, int demandIndex, // Locate demand category record and assign demandName to it list_t *dlist = p->network.Node[nodeIndex].D; - list_node_t *lnode = get_nth_list(dlist, demandIndex); - if (!lnode) - return 253; - else - set_category_name(lnode, demandName); + if (!dlist) { + dlist = create_demand_list(0, 0, demandName); + if (!dlist) return 101; + p->network.Node[nodeIndex].D = dlist; + } + else { + list_node_t *lnode = get_nth_list(dlist, demandIndex); + if (!lnode) + return 253; + else + set_category_name(lnode, demandName); + } return 0; } @@ -2960,11 +2976,19 @@ int DLLEXPORT EN_setdemandpattern(EN_Project p, int nodeIndex, int demandIndex, if (nodeIndex <= net->Njuncs) { list_t *dlist = p->network.Node[nodeIndex].D; - list_node_t *lnode = get_nth_list(dlist, demandIndex); - if (!lnode) - return 253; - else - set_pattern_index(lnode, patIndex); + if (!dlist) { + dlist = create_demand_list(0, patIndex, NULL); + if (!dlist) return 101; + + p->network.Node[nodeIndex].D = dlist; + } + else { + list_node_t *lnode = get_nth_list(dlist, demandIndex); + if (!lnode) + return 253; + else + set_pattern_index(lnode, patIndex); + } } return 0; } diff --git a/src/input3.c b/src/input3.c index 161f2ab..9837bd4 100644 --- a/src/input3.c +++ b/src/input3.c @@ -124,22 +124,11 @@ int juncdata(Project *pr) // create demand data only if a demand has been specified if (y != 0.0) { - demand_data_t *demand_data; - - demand_list = create_list(get_demand_data_size(), delete_demand_data); - if (demand_list == NULL) return 101; - // apply the default demand pattern and append the data if (p == 0) p = findpattern(net, parser->DefPatID); - demand_data = create_demand_data(y, p, NULL); - if (demand_data == NULL) return 101; - - append_list(demand_list, &demand_data); + demand_list = create_demand_list(y, p, NULL); + if (!demand_list) return 101; } - //demand->Base = y; - //demand->Pat = p; - //demand->Name = NULL; - //demand->next = NULL; node->D = demand_list; hyd->NodeDemand[njuncs] = y; diff --git a/src/util/list.c b/src/util/list.c index c74e2c2..0b568d9 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -120,7 +120,7 @@ list_node_t *head_list(list_t *list, bool removeFromList) // Warning: When node is removed caller is responsible for freeing it. // { - assert(list->head != NULL); +// assert(list->head != NULL); if (list) { list_node_t *node = list->head; diff --git a/tests/test_demand_data.cpp b/tests/test_demand_data.cpp index 6428cc0..8d7252c 100644 --- a/tests/test_demand_data.cpp +++ b/tests/test_demand_data.cpp @@ -36,6 +36,17 @@ boost::test_tools::predicate_result check_string(std::string test, std::string r BOOST_AUTO_TEST_SUITE(test_demand_data) +BOOST_AUTO_TEST_CASE(test_create_destroy_demand_list) +{ + list_t *dlist; + + dlist = create_demand_list(100.0, 1, "CUB_SCOUT_DAY_CAMP"); + BOOST_CHECK(dlist != NULL); + + delete_list(dlist); +} + + BOOST_AUTO_TEST_CASE (test_create_destroy) { void *data = NULL; @@ -140,7 +151,7 @@ BOOST_FIXTURE_TEST_CASE(test_convert_demand, Fixture) BOOST_TEST(demand == 6.31, boost::test_tools::tolerance(0.01)); } -BOOST_AUTO_TEST_CASE(test_openclose) +BOOST_AUTO_TEST_CASE(test_initclose) { int error; @@ -148,7 +159,7 @@ BOOST_AUTO_TEST_CASE(test_openclose) EN_createproject(&ph); - error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); + error = EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_GPM, EN_HW); BOOST_REQUIRE(error == 0); error = EN_close(ph); @@ -163,85 +174,173 @@ BOOST_AUTO_TEST_CASE(test_openclose) #define DATA_PATH_RPT "./test.rpt" #define DATA_PATH_OUT "./test.out" -struct FixtureOpenClose { - FixtureOpenClose() { + +struct FixtureSingleNode { + FixtureSingleNode() { error = 0; ph = NULL; EN_createproject(&ph); - error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); + EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_GPM, EN_HW); + + EN_addnode(ph, (char *)"N2", EN_JUNCTION); + EN_getnodeindex(ph, (char *)"N2", &node_idx); } - ~FixtureOpenClose() { - error = EN_close(ph); + ~FixtureSingleNode() { + EN_close(ph); EN_deleteproject(&ph); } - - int error; + int error, node_idx; EN_Project ph; }; -BOOST_FIXTURE_TEST_CASE(test_demandname_getset, FixtureOpenClose) -{ - int Nindex, ndem; - error = EN_getnodeindex(ph, (char *)"12", &Nindex); +BOOST_FIXTURE_TEST_CASE(test_single_node, FixtureSingleNode) +{ + int demand_idx, pattern_idx, n; + double demand; + + error = EN_getnumdemands(ph, node_idx, &n); BOOST_REQUIRE(error == 0); - error = EN_getnumdemands(ph, Nindex, &ndem); - BOOST_REQUIRE(error == 0); - BOOST_CHECK(ndem == 1); + BOOST_CHECK(n == 0); + + demand_idx = 1; + error = EN_getbasedemand(ph, node_idx, demand_idx, &demand); + BOOST_REQUIRE(error == 253); + + error = EN_getdemandpattern(ph, node_idx, demand_idx, &pattern_idx); + BOOST_REQUIRE(error == 253); char demname[31]; - - error = EN_getdemandname(ph, Nindex, ndem, demname); - BOOST_REQUIRE(error == 0); + error = EN_getdemandname(ph, node_idx, demand_idx, demname); + BOOST_REQUIRE(error == 253); BOOST_CHECK(check_string(demname, "\0")); - error = EN_setdemandname(ph, Nindex, ndem, (char *)"Demand category name"); + error = EN_setbasedemand(ph, node_idx, demand_idx, 100.0); BOOST_REQUIRE(error == 0); - error = EN_getdemandname(ph, Nindex, ndem, demname); + // only one demand category + pattern_idx = 1; + error = EN_setdemandpattern(ph, node_idx, demand_idx, pattern_idx); + BOOST_REQUIRE(error == 205); + + // create pattern + error = EN_addpattern(ph, (char *)"Pat2"); BOOST_REQUIRE(error == 0); - BOOST_CHECK(check_string(demname, "Demand category name")); + error = EN_getpatternindex(ph, (char *)"Pat2", &pattern_idx); + BOOST_REQUIRE(error == 0); + + error = EN_setdemandpattern(ph, node_idx, demand_idx, pattern_idx); + BOOST_REQUIRE(error == 0); + + error = EN_setdemandname(ph, node_idx, demand_idx, (char *)"CUB_SCOUT_MESS_HALL"); + BOOST_REQUIRE(error == 0); + } -BOOST_FIXTURE_TEST_CASE(test_demandpattern_get, FixtureOpenClose) + +BOOST_FIXTURE_TEST_CASE(test_pattern_edits, FixtureSingleNode) { - int n, patIdx; + int n, pat_idx; - error = EN_getdemandpattern(ph, 3, 1, &patIdx); + // Add 2 new patterns + error = EN_addpattern(ph, (char *)"Pat2"); BOOST_REQUIRE(error == 0); - - error = EN_getpatternlen(ph, patIdx, &n); - BOOST_REQUIRE(error == 0); - - BOOST_CHECK(n == 12); -} - -BOOST_FIXTURE_TEST_CASE(test_demandpattern_getset, FixtureOpenClose) -{ - int n, patIdx; - - double f3[] = { 3.1, 3.2, 3.3, 3.4 }; - - // Create pattern error = EN_addpattern(ph, (char *)"Pat3"); BOOST_REQUIRE(error == 0); + double f2[] = { 2.1, 2.2 }; + double f3[] = { 3.1, 3.2, 3.3, 3.4 }; + error = EN_setpattern(ph, 2, f2, 2); + BOOST_REQUIRE(error == 0); error = EN_setpattern(ph, 3, f3, 4); BOOST_REQUIRE(error == 0); - + // Assign Pat3 to 3rd junction error = EN_setdemandpattern(ph, 3, 1, 3); BOOST_REQUIRE(error == 0); - - error = EN_getdemandpattern(ph, 3, 1, &patIdx); + // Delete Pat2 + error = EN_deletepattern(ph, 2); BOOST_REQUIRE(error == 0); - - error = EN_getpatternlen(ph, patIdx, &n); + + //Check that there are now 2 patterns + error = EN_getcount(ph, EN_PATCOUNT, &n); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(n == 2); + + // Check that Pat3 with 4 factors is still assigned to 3rd junction + error = EN_getdemandpattern(ph, 3, 1, &pat_idx); + BOOST_REQUIRE(error == 0); + error = EN_getpatternlen(ph, pat_idx, &n); BOOST_REQUIRE(error == 0); BOOST_CHECK(n == 4); } + +//BOOST_FIXTURE_TEST_CASE(test_demandpattern_getset, FixtureOpenClose) +//{ +// int n, patIdx, pat2Idx, pat3Idx, defPatIdx = 1; +// +// // Rename the default pattern +// error = EN_setpatternid(ph, defPatIdx, (char *)"Pat1"); +// BOOST_REQUIRE(error == 0); +// error = EN_getpatternindex(ph, (char *)"Pat1", &patIdx); +// BOOST_REQUIRE(error == 0); +// BOOST_CHECK(defPatIdx == patIdx); +// +// // Add 2 new patterns +// error = EN_addpattern(ph, (char *)"Pat2"); +// BOOST_REQUIRE(error == 0); +// error = EN_getpatternindex(ph, (char *)"Pat2", &pat2Idx); +// BOOST_REQUIRE(error == 0); +// +// error = EN_addpattern(ph, (char *)"Pat3"); +// BOOST_REQUIRE(error == 0); +// error = EN_getpatternindex(ph, (char *)"Pat3", &pat3Idx); +// BOOST_REQUIRE(error == 0); +// +// double f2[] = {2.1, 2.2}; +// double f3[] = {3.1, 3.2, 3.3, 3.4}; +// error = EN_setpattern(ph, pat2Idx, f2, 2); +// BOOST_REQUIRE(error == 0); +// error = EN_setpattern(ph, pat3Idx, f3, 4); +// BOOST_REQUIRE(error == 0); +// +// // Assign Pat3 to 3rd junction +// error = EN_setdemandpattern(ph, 3, 1, pat3Idx); +// BOOST_REQUIRE(error == 0); +// +// // Delete Pat2 and check for 2 patterns +// //error = EN_deletepattern(ph, pat2Idx); +// //BOOST_REQUIRE(error == 0); +// //error = EN_getcount(ph, EN_PATCOUNT, &n); +// //BOOST_REQUIRE(error == 0); +// //BOOST_CHECK(n == 2); +// +// // Check that Pat3 with 4 factors is still assigned to 3rd junction +// error = EN_getdemandpattern(ph, 3, 1, &patIdx); +// BOOST_REQUIRE(error == 0); +// error = EN_getpatternlen(ph, patIdx, &n); +// BOOST_REQUIRE(error == 0); +// BOOST_CHECK(n == 4); +// +// // Delete the default pattern +// //error = EN_deletepattern(ph, defPatIdx); +// //BOOST_REQUIRE(error == 0); +// +// // Check that junction 4 has no pattern +// error = EN_getdemandpattern(ph, 4, 1, &patIdx); +// BOOST_REQUIRE(error == 0); +// BOOST_CHECK(patIdx == 0); +// +// // And that junction 3 still uses Pat3 +// error = EN_getdemandpattern(ph, 3, 1, &pat3Idx); +// BOOST_REQUIRE(error == 0); +// error = EN_getpatternindex(ph, (char *)"Pat3", &patIdx); +// BOOST_REQUIRE(error == 0); +// BOOST_CHECK(pat3Idx == patIdx); +//} + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/test_pattern.cpp b/tests/test_pattern.cpp index ef2eb71..01af33d 100644 --- a/tests/test_pattern.cpp +++ b/tests/test_pattern.cpp @@ -18,7 +18,51 @@ BOOST_AUTO_TEST_SUITE (pattern) -BOOST_AUTO_TEST_CASE(add_set_pattern) +BOOST_FIXTURE_TEST_CASE(test_set_get_default_pattern, FixtureOpenClose) +{ + // Assign the default pattern index + int defPatIdx = 1; + int patIdx; + + // Rename the default pattern + error = EN_setpatternid(ph, defPatIdx, (char *)"Pat1"); + BOOST_REQUIRE(error == 0); + + error = EN_getpatternindex(ph, (char *)"Pat1", &patIdx); + BOOST_REQUIRE(error == 0); + + BOOST_CHECK(defPatIdx == patIdx); +} + +BOOST_FIXTURE_TEST_CASE(test_add_delete, FixtureOpenClose) +{ + double f2[] = { 2.1, 2.2 }; + double f3[] = { 3.1, 3.2, 3.3, 3.4 }; + + // Add 2 new patterns + error = EN_addpattern(ph, (char *)"Pat2"); + BOOST_REQUIRE(error == 0); + error = EN_addpattern(ph, (char *)"Pat3"); + BOOST_REQUIRE(error == 0); + + error = EN_setpattern(ph, 2, f2, 2); + BOOST_REQUIRE(error == 0); + error = EN_setpattern(ph, 3, f3, 4); + BOOST_REQUIRE(error == 0); + + // Delete Pat2 + error = EN_deletepattern(ph, 2); + BOOST_REQUIRE(error == 0); + + // Check that there are now 2 patterns + int n; + error = EN_getcount(ph, EN_PATCOUNT, &n); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(n == 2); +} + + +BOOST_AUTO_TEST_CASE(test_add_set) { std::string path_inp(DATA_PATH_NET1); std::string path_rpt(DATA_PATH_RPT); @@ -34,7 +78,7 @@ BOOST_AUTO_TEST_CASE(add_set_pattern) BOOST_REQUIRE(error == 0); // Assign the default pattern index - int defPatIdx = 1; + int n, defPatIdx = 1; int patIdx; // Rename the default pattern @@ -56,8 +100,7 @@ BOOST_AUTO_TEST_CASE(add_set_pattern) // Delete Pat2 EN_deletepattern(ph, 2); - // Check that there are now 2 patterns - int n; + //Check that there are now 2 patterns EN_getcount(ph, EN_PATCOUNT, &n); BOOST_REQUIRE(n == 2);