• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

urbanopt / geojson-modelica-translator / 9766694116

02 Jul 2024 07:13PM UTC coverage: 88.188% (-0.5%) from 88.687%
9766694116

push

github

web-flow
Templates and tests for horizontal piping modeling (#627)

* Add customized mo files

* Add kIns and use each

* Introduce a new template for ground coupling

* Supplemental table for calculating soil temperature

* Placeholder python file for ground coupling

* Pass more pipe material parameters

* Add example sys_pamas file for tests

* Modified ground coupling template

* Ground coupling instance

* Update package names

* Modify dis to take more inputs

* Update py file, not final yet

* Update ground_coupling.py

* add method to read a feature from a geojson file by id

* method to read a geojson feature from a jsonpath

* code to read from geojson to templtate

* add test line to attempt injecting from geojson into template

* test for ground_coupling

* empty ground_coupling coupling templates - WIP

* update dependencies

* Add equations for calculating wall thickness

* Add function for searching for weather station

* finalize py file

* get pipe lengths in datDes

* build new coupling

* move dis instance to new coupling

* Access data of sys_params

* Move things in coupling

* Fix typo

* Change pipe length list to be global

* Modify test to instantiate ground coupling

* Reading geojson in district.py, might cause problem to other district tests

* New geojson with thermal connectors for testing

* Modify parameter paths

* Update geojson file name in test

* Rearrange couplings

* Update coupling list in test

* Fix within statements

* Update some parameters

* Update access to borefield id

* Update access to num_buildings in template

* Add TODO

* Change pump input type

* Change how lDis and lEnd are populated

* Replace sqaure brackets

* Convert ft to meter

* Pre-commit changes

* skip a lint check in district.py. A different PR refactors this, so ignore for now

* format modelica code via pre-commit

* Avoid using excel reader

... (continued)

955 of 1165 branches covered (81.97%)

Branch coverage included in aggregate %.

80 of 94 new or added lines in 5 files covered. (85.11%)

2 existing lines in 1 file now uncovered.

2651 of 2924 relevant lines covered (90.66%)

1.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.0
/geojson_modelica_translator/geojson/urbanopt_geojson.py
1
# :copyright (c) URBANopt, Alliance for Sustainable Energy, LLC, and other contributors.
2
# See also https://github.com/urbanopt/geojson-modelica-translator/blob/develop/LICENSE.md
3

4
import logging
2✔
5
from pathlib import Path
2✔
6

7
import geojson
2✔
8
from jsonpath_ng.ext import parse
2✔
9

10
from geojson_modelica_translator.geojson.schemas import Schemas
2✔
11

12
_log = logging.getLogger(__name__)
2✔
13

14

15
class GeoJsonValidationError(Exception):
2✔
16
    pass
2✔
17

18

19
# TODO: Inherit from GeoJSON Feature class, move to its own file
20
class UrbanOptLoad:
2✔
21
    """An UrbanOptLoad is a container for holding Building-related data in a dictionary. This object
22
    does not do much work on the GeoJSON definition of the data at the moment, rather it creates
23
    an isolation layer between the GeoJSON data and the GMT.
24
    """
25

26
    def __init__(self, feature):
2✔
27
        self.feature = feature
2✔
28
        self.id = feature.get("properties", {}).get("id", None)
2✔
29

30
        # do some validation
31
        if self.id is None:
2!
32
            raise GeoJsonValidationError("GeoJSON feature requires an ID property but value was null")
×
33

34
    def __str__(self):
2✔
35
        return f"ID: {self.id}"
×
36

37

38
class UrbanOptGeoJson:
2✔
39
    """Root class for parsing an URBANopt GeoJSON file. This class simply reads and parses
40
    URBANopt GeoJSON files.
41
    """
42

43
    def __init__(self, filename, building_ids=None):
2✔
44
        """Initialize the UrbanOptGeoJson object by reading the GeoJSON file
45

46
        :param filename: str, path to the GeoJSON file to parse
47
        :param building_ids: list[str | int] | None, optional, list of GeoJSON building
48
            IDs to parse from the file. If None or an empty list, parse all buildings.
49
        """
50
        if not Path(filename).exists():
2✔
51
            raise GeoJsonValidationError(f"URBANopt GeoJSON file does not exist: {filename}")
2✔
52

53
        with open(filename) as f:
2✔
54
            self.data = geojson.load(f)
2✔
55

56
        self.schemas = Schemas()
2✔
57

58
        errors = ""
2✔
59
        building_errors = {}
2✔
60
        self.buildings = []
2✔
61
        for feature in self.data.features:
2✔
62
            if feature["properties"]["type"] == "Building":
2✔
63
                building = UrbanOptLoad(feature)
2✔
64
                if not building_ids or building.id in building_ids:
2✔
65
                    # Ignore validation failures for features with 'detailed_model_filename' in the properties
66
                    # Buildings defined by an osm don't have all keys in geojson, therefore will always fail validation
67
                    if "detailed_model_filename" not in feature["properties"]:
2!
68
                        errors = self.schemas.validate("building", building.feature.properties)
2✔
69
                    if errors:
2✔
70
                        building_errors[building.id] = errors
2✔
71
                    else:
72
                        self.buildings.append(building)
2✔
73

74
        if building_errors:
2✔
75
            formatted_errors = ""
2✔
76
            for building_id, errors in building_errors.items():
2✔
77
                building_errors_bullets = "".join([f"\n    * {error}" for error in errors])
2✔
78
                formatted_errors += f"\n  ID {building_id}:{building_errors_bullets}"
2✔
79

80
            message = f"GeoJSON file is not valid:{formatted_errors}"
2✔
81
            raise GeoJsonValidationError(message)
2✔
82

83
        if not self.buildings:
2!
84
            raise GeoJsonValidationError(f"No valid buildings found in GeoJSON file: {filename}")
×
85

86
    def get_feature_by_id(self, feature_id=None):
2✔
87
        """return geojson data for a specific feature (building, pipe, wire, junction, district system, etc).
88

89
        :param feature_id: string, id of the object to look up in the geojson file
90
        :return: dict, full feature data for the object with the given id
91
        """
92

NEW
93
        if feature_id is None:
×
NEW
94
            raise SystemExit("No id submitted. Please retry and include the appropriate id")
×
95

NEW
96
        for feature in self.data.features:
×
NEW
97
            if feature["properties"]["id"] == str(feature_id):
×
NEW
98
                return feature
×
99

100
    def get_feature(self, jsonpath):
2✔
101
        """Return the parameter(s) from a jsonpath.
102

103
        :param path: string, period delimited path of the data to retrieve
104
        :return: dict, full feature data for the object with the given id
105
        """
106

107
        if jsonpath is None or jsonpath == "":
2!
NEW
108
            return None
×
109

110
        matches = parse(jsonpath).find(self.data)
2✔
111

112
        results = []
2✔
113
        for match in matches:
2✔
114
            results.append(match.value)
2✔
115

116
        if len(results) == 1:
2!
117
            # If only one value, then return that value and not a list of values
NEW
118
            results = results[0]
×
119
        elif len(results) == 0:
2!
NEW
120
            return print(f"No matches found for jsonpath {jsonpath}")
×
121

122
        # otherwise return the list of values
123
        return results
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc