def to_modelica(self, scaffold):
        """
        Create indirect cooling models based on the data in the buildings and geojsons

        :param scaffold: Scaffold object, Scaffold of the entire directory of the project.
        """
        cooling_indirect_template = self.template_env.get_template(
            "CoolingIndirect.mot")

        ets_data = self.system_parameters.get_param_by_building_id(
            self._geojson_load_id, 'ets_model_parameters.indirect')

        combined_template_data = {**ets_data, **self.district_template_data}

        self.run_template(
            template=cooling_indirect_template,
            save_file_name=os.path.join(scaffold.project_path, 'Substations',
                                        f'{self._model_filename}.mo'),
            project_name=scaffold.project_name,
            model_filename=self._model_filename,
            ets_data=combined_template_data,
        )

        # now create the Package level package. This really needs to happen at the GeoJSON to modelica stage, but
        # do it here for now to aid in testing.
        package = PackageParser(scaffold.project_path)
        if 'Substations' not in package.order:
            package.add_model('Substations')
            package.save()

        package_models = [self._model_filename]
        ets_package = PackageParser(scaffold.substations_path.files_dir)
        if ets_package.order_data is None:
            ets_package = PackageParser.new_from_template(
                path=scaffold.substations_path.files_dir,
                name="Substations",
                order=package_models,
                within=scaffold.project_name)
        else:
            for model_name in package_models:
                if model_name not in ets_package.order:
                    ets_package.add_model(model_name)
        ets_package.save()
    def post_process(self, scaffold):
        """
        Cleanup the export of TimeSeries files into a format suitable for the district-based analysis. This includes
        the following:
            * Add a Loads project
            * Add a project level project

        :param scaffold: Scaffold object, Scaffold of the entire directory of the project.
        :return: None
        """
        order_files = [Path(mo).stem for mo in self.required_mo_files]
        order_files += self.template_files_to_include
        b_modelica_path = Path(
            scaffold.loads_path.files_dir) / self.building_name
        new_package = PackageParser.new_from_template(
            path=b_modelica_path,
            name=self.building_name,
            order=order_files,
            within=f"{scaffold.project_name}.Loads")
        new_package.save()

        # now create the Loads level package and package.order.
        if not os.path.exists(
                os.path.join(scaffold.loads_path.files_dir, 'package.mo')):
            load_package = PackageParser.new_from_template(
                scaffold.loads_path.files_dir,
                "Loads", [self.building_name],
                within=f"{scaffold.project_name}")
            load_package.save()
        else:
            load_package = PackageParser(
                os.path.join(scaffold.loads_path.files_dir))
            load_package.add_model(self.building_name)
            load_package.save()

        # now create the Package level package. This really needs to happen at the GeoJSON to modelica stage, but
        # do it here for now to aid in testing.
        pp = PackageParser.new_from_template(scaffold.project_path,
                                             scaffold.project_name, ["Loads"])
        pp.save()
    def post_process(self, scaffold, keep_original_models=False):
        """Cleanup the export of the TEASER files into a format suitable for the district-based analysis.
        This includes the following:

            * Update the partial to inherit from the GeojsonExport class defined in MBL.
            * Rename the files to remove the names of the buildings
            * Move the files to the Loads level and remove the Project folder (default export method from TEASER)
            * Add heat port
            * Add return temperature
            * Add fluid ports for the indoor air volume.
            * Remove weaDat and rely on weaBus
            * Add latent fraction multiplier
            * Add TAir output
            * Add TRad output
            * Add nPorts variable
            * Propagate use of moisture balance
            * Wrap the thermal zones into a single model

        :param scaffold: Scaffold object, Scaffold of the entire directory of the project.
        :param keep_original_models: boolean, do not delete the original models generated by TEASER
        :return: None
        """

        teaser_building = self.template_env.get_template("TeaserBuilding.mot")
        teaser_coupling = self.template_env.get_template(
            "TeaserCouplingBuilding.mot")
        run_coupling_template = self.template_env.get_template(
            "RunTeaserCouplingBuilding.most")

        # This for loop does *a lot* of work to make the models compatible for the project structure.
        # Need to investigate moving this into a more testable location.
        # create a list of strings that we need to replace in all the file as we go along
        string_replace_list = []
        mos_weather_filename = self.system_parameters.get_param_by_building_id(
            self.building_id, "load_model_parameters.rc.mos_weather_filename")
        # create a new modelica based path for the buildings # TODO: make this work at the toplevel, somehow.
        b_modelica_path = ModelicaPath(self.building_name,
                                       scaffold.loads_path.files_dir, True)

        # copy over the entire model to the new location
        copytree(
            os.path.join(
                scaffold.loads_path.files_dir,
                f"Project/{self.building_name}/{self.building_name}_Models"),
            b_modelica_path.files_dir,
        )

        # read in the package to apply the changes as they other files are processed
        # TODO: these should be linked, so a rename method should act across the model and the package.order
        package = PackageParser(
            os.path.join(scaffold.loads_path.files_dir, self.building_name))

        # move the internal gains files to a new resources folder
        mat_files = glob.glob(
            os.path.join(scaffold.loads_path.files_dir,
                         f"{self.building_name}/*.txt"))
        for f in mat_files:
            new_file_name = os.path.basename(f).replace(self.building_name, "")
            os.rename(f, f"{b_modelica_path.resources_dir}/{new_file_name}")

            # The main branch of teaser has yet to merge in the changes to support the fixes to the
            # internal gain files. The next method can be removed once the TEASER development branch is
            # merged into master/main and released.
            self.fix_gains_file(
                f"{b_modelica_path.resources_dir}/{new_file_name}")

            string_replace_list.append((
                f"Project/{self.building_name}/{self.building_name}_Models/{os.path.basename(f)}",
                f"{scaffold.project_name}/Loads/{b_modelica_path.resources_relative_dir}/{new_file_name}",
            ))

        # process each of the thermal zones
        thermal_zone_files = []
        mo_files = glob.glob(
            os.path.join(scaffold.loads_path.files_dir,
                         f"{self.building_name}/*.mo"))
        for f in mo_files:
            # ignore the package.mo file
            if os.path.basename(f) in ["package.mo"]:
                continue

            mofile = Model(f)

            # previous paths and replace with the new one.
            # Make sure to update the names of any resources as well.
            mofile.set_within_statement(
                f'{scaffold.project_name}.Loads.{self.building_name}')

            # remove ReaderTMY3
            mofile.remove_component(
                "Buildings.BoundaryConditions.WeatherData.ReaderTMY3",
                "weaDat")

            # updating path to internal loads
            for s in string_replace_list:
                new_file_path = s[1]
                new_resource_arg = f'''Modelica.Utilities.Files.loadResource("modelica://{new_file_path}")'''
                old_file_path = s[0]
                old_resource_arg = f'''Modelica.Utilities.Files.loadResource("modelica://{old_file_path}")'''

                mofile.update_component_modification(
                    "Modelica.Blocks.Sources.CombiTimeTable",
                    "internalGains",
                    "fileName",
                    new_resource_arg,
                    if_value=old_resource_arg)

            # add heat port convective heat flow.
            mofile.insert_component(
                "Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a",
                "port_a",
                string_comment='Heat port for convective heat flow.',
                annotations=[
                    "Placement(transformation(extent={{-10,90},{10,110}}), "
                    "iconTransformation(extent={{-10,90},{10,110}}))"
                ])
            # add heat port radiative heat flow.
            mofile.insert_component(
                "Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a",
                "port_b",
                string_comment='Heat port for radiative heat flow.',
                annotations=[
                    "Placement(transformation(extent={{30,-110},{50,-90}}, "
                    "iconTransformation(extent={{40,-112},{60,-92}})))"
                ])
            # add fluid ports for the indoor air volume.
            mofile.insert_component(
                "Modelica.Fluid.Vessels.BaseClasses.VesselFluidPorts_b",
                "ports[nPorts]",
                string_comment=
                'Auxiliary fluid inlets and outlets to indoor air volume.',
                modifications={
                    'redeclare each final package Medium':
                    'Buildings.Media.Air'
                },
                annotations=[
                    "Placement(transformation(extent={{-30, -8}, {30, 8}},origin={0, -100}), "
                    "iconTransformation(extent={{-23.25, -7.25}, {23.25, 7.25}},"
                    "origin={-0.75, -98.75}))"
                ])

            fraction_latent_person = self.system_parameters.get_param(
                "buildings.default.load_model_parameters.rc.fraction_latent_person",
                default=1.25)

            use_moisture_balance = self.system_parameters.get_param(
                "buildings.default.load_model_parameters.rc.use_moisture_balance",
                default='false')

            n_ports = self.system_parameters.get_param(
                "buildings.default.load_model_parameters.rc.nPorts", default=0)

            # create a new parameter for fraction latent person
            mofile.add_parameter(
                'Real',
                'fraLat',
                assigned_value=fraction_latent_person,
                string_comment=
                'Fraction latent of sensible persons load = 0.8 for home, 1.25 for office.'
            )
            # create a new Boolean parameter to evaluate the persons latent loads.
            mofile.add_parameter(
                'Boolean',
                'use_moisture_balance',
                assigned_value=use_moisture_balance,
                string_comment=
                'If true, input connector QLat_flow is enabled and room air computes'
                ' moisture balance.')
            # create a integer parameter to evaluate number of connected ports.
            mofile.add_parameter('Integer',
                                 'nPorts',
                                 assigned_value=n_ports,
                                 string_comment='Number of fluid ports.',
                                 annotations=['connectorSizing=true'])
            # Set the fraction latent person in the template by simply replacing the value
            mofile.insert_component(
                'Modelica.Blocks.Sources.RealExpression',
                'perLatLoa',
                modifications={
                    'y': 'internalGains.y[2]*fraLat',
                },
                conditional='if use_moisture_balance',
                string_comment='Latent person loads',
                annotations=[
                    'Placement(transformation(extent={{-80,-60},{-60,-40}}))'
                ])

            # add TRad output
            mofile.insert_component(
                'Buildings.Controls.OBC.CDL.Interfaces.RealOutput',
                'TRad',
                modifications={
                    'quantity': '"ThermodynamicTemperature"',
                    'unit': '"K"',
                    'displayUnit': '"degC"',
                },
                string_comment='Mean indoor radiation temperature',
                annotations=[
                    'Placement(transformation(extent={{100,-10},{120,10}}))'
                ])

            # All existing weaDat.weaBus connections need to be updated to simply weaBus
            # (except for the connections where 'weaBus' is port_b, we will just delete these)
            mofile.edit_connect('weaDat.weaBus',
                                '!weaBus',
                                new_port_a='weaBus')
            # Now remove the unnecessary weaDat.weaBus -> weaBus connection
            mofile.remove_connect('weaDat.weaBus', 'weaBus')

            # add new port connections
            rc_order = self.system_parameters.get_param_by_building_id(
                self.building_id, "load_model_parameters.rc.order", default=2)
            thermal_zone_name = None
            thermal_zone_type = None
            if rc_order == 1:
                thermal_zone_type = 'OneElement'
                thermal_zone_name = 'thermalZoneOneElement'
            elif rc_order == 2:
                thermal_zone_type = 'TwoElements'
                thermal_zone_name = 'thermalZoneTwoElements'
            elif rc_order == 3:
                thermal_zone_type = 'ThreeElements'
                thermal_zone_name = 'thermalZoneThreeElements'
            elif rc_order == 4:
                thermal_zone_type = 'FourElements'
                thermal_zone_name = 'thermalZoneFourElements'

            if thermal_zone_name is not None and thermal_zone_type is not None:
                # add TAir output - This has been moved away from the other insert_component blocks
                # to use thermal_zone_name
                mofile.insert_component(
                    'Buildings.Controls.OBC.CDL.Interfaces.RealOutput',
                    'TAir',
                    modifications={
                        'quantity': '"ThermodynamicTemperature"',
                        'unit': '"K"',
                        'displayUnit': '"degC"',
                    },
                    conditional=
                    f'if {thermal_zone_name}.ATot > 0 or {thermal_zone_name}.VAir > 0',
                    string_comment='Room air temperature',
                    annotations=[
                        'Placement(transformation(extent={{100,38},{120,58}}))'
                    ])

                # In TEASER 0.7.5 the hConvWinOut, hConvExt, hConvWin, hConvInt, hConvFloor, hConvRoof in various of
                # the ReducedOrder models should be hCon* not hConv*. This has been fixed on the development branch
                # of TEASER, but the team doesn't appear to be releasing nor merging the development branch (yet).
                mofile.rename_component_argument(
                    "Buildings.ThermalZones.ReducedOrder.EquivalentAirTemperature.VDI6007WithWindow",
                    "eqAirTemp", "hConvWallOut", "hConWallOut")
                mofile.rename_component_argument(
                    "Buildings.ThermalZones.ReducedOrder.EquivalentAirTemperature.VDI6007WithWindow",
                    "eqAirTemp", "hConvWinOut", "hConWinOut")

                mofile.rename_component_argument(
                    "Buildings.ThermalZones.ReducedOrder.EquivalentAirTemperature.VDI6007",
                    "eqAirTempVDI", "hConvWallOut", "hConWallOut")

                renames = {
                    "hConvExt": "hConExt",
                    "hConvFloor": "hConFloor",
                    "hConvRoof": "hConRoof",
                    "hConvWinOut": "hConWinOut",
                    "hConvWin": "hConWin",
                    "hConvInt": "hConInt",
                }
                for from_, to_ in renames.items():
                    mofile.rename_component_argument(
                        f"Buildings.ThermalZones.ReducedOrder.RC.{thermal_zone_type}",
                        thermal_zone_name, from_, to_)

                mofile.update_component_modifications(
                    f"Buildings.ThermalZones.ReducedOrder.RC.{thermal_zone_type}",
                    thermal_zone_name,
                    {"use_moisture_balance": "use_moisture_balance"})

                mofile.update_component_modifications(
                    f"Buildings.ThermalZones.ReducedOrder.RC.{thermal_zone_type}",
                    thermal_zone_name, {"nPorts": "nPorts"})

                mofile.add_connect(
                    'port_a',
                    f'{thermal_zone_name}.intGainsConv',
                    annotations=[
                        'Line(points={{0,100},{96,100},{96,20},{92,20}}, color={191,0,0})'
                    ])

                mofile.add_connect(
                    f'{thermal_zone_name}.TAir',
                    'TAir',
                    annotations=[
                        'Line(points={{93,32},{98,32},{98,48},{110,48}}, color={0,0,127})'
                    ])
                mofile.add_connect(
                    f'{thermal_zone_name}.TRad',
                    'TRad',
                    annotations=[
                        'Line(points={{93,28},{98,28},{98,-20},{110,-20}}, color={0,0,127})'
                    ])
                mofile.add_connect(
                    f'{thermal_zone_name}.QLat_flow',
                    'perLatLoa.y',
                    annotations=[
                        'Line(points={{43,4},{40,4},{40,-28},{-40,-28},{-40,-50},{-59,-50}}, color={0, 0,127})'
                    ])

                mofile.add_connect(
                    f'{thermal_zone_name}.intGainsRad',
                    'port_b',
                    annotations=[
                        'Line(points={{92, 24}, {98, 24}, {98, -100}, {40, -100}}, color={191, 0, 0})'
                    ])
                mofile.insert_equation_for_loop(
                    index_identifier="i",
                    expression_raw="1:nPorts",
                    loop_body_raw_list=[
                        "connect(ports[i], thermalZoneFourElements.ports[i])",
                        "\tannotation (Line(",
                        "\tpoints={{-18,-102},{-18,-84},{83,-84},{83,-1.95}},",
                        "\tcolor={0,127,255},",
                        "\tsmooth=Smooth.None));",
                    ],
                )

            # change the name of the modelica model to remove the building id, update in package too!
            original_model_name = mofile.get_name()
            new_model_name = original_model_name.split("_")[1]
            thermal_zone_files.append(new_model_name)
            package.rename_model(original_model_name, new_model_name)
            mofile.set_name(new_model_name)

            # Save as the new filename (without building ID)
            new_filename = os.path.join(
                scaffold.loads_path.files_dir,
                f'{self.building_name}/{os.path.basename(f).split("_")[1]}')
            mofile.save_as(new_filename)
            os.remove(f)

        # Now connect all the thermal zone files into the teaser building
        # 1. Need to a map of thermal zone names and instances
        zone_list = []
        for index, tz in enumerate(thermal_zone_files):
            # take /a/file/Meeting.mo -> zone_map["Meeting"] = "meeting"
            tz_process = os.path.splitext(os.path.basename(tz))[0]
            zone_list.append({
                "index":
                index,
                "model_name":
                tz_process,
                "instance_name":
                tz_process.lower(),
                # process where this will be stored in python otherwise too many {{}}, yes ridiculous.
                # This needs to result in {{a,b},{x,y}}
                "placement":
                f"{{{{{-160 + index * 40},-20}},{{{-140 + index * 40},0}}}}"
            })

        # Handle setting nominal load for IT room zone
        nom_cool_flow = np.array([-10000] * len(zone_list))
        for i, dic in enumerate(zone_list):
            if dic["instance_name"] == "ict":
                print("setting coo flow")
                nom_cool_flow[
                    i - 1] = -50000  # Need to offset for different indexing
        nom_heat_flow = np.array([10000] * len(zone_list))
        building_template_data = {
            "thermal_zones":
            zone_list,
            "nominal_heat_flow":
            str(repr(nom_heat_flow))[1:-1].replace("[", "{").replace(
                "]", "}").split("rray(", 1)[-1],
            "nominal_cool_flow":
            str(repr(nom_cool_flow))[1:-1].replace("[", "{").replace(
                "]", "}").split("rray(", 1)[-1],
            "load_resources_path":
            b_modelica_path.resources_relative_dir,
            "mos_weather": {
                "mos_weather_filename": mos_weather_filename,
                "filename": os.path.basename(mos_weather_filename),
                "path": os.path.dirname(mos_weather_filename),
            },
            "nominal_values": {
                # Adding 273.15 to convert from C to K (for absolute temps, not relative temps)
                "chw_supply_temp":
                self.system_parameters.get_param_by_building_id(
                    self.building_id,
                    "load_model_parameters.rc.temp_chw_supply") + 273.15,
                "chw_return_temp":
                self.system_parameters.get_param_by_building_id(
                    self.building_id,
                    "load_model_parameters.rc.temp_chw_return") + 273.15,
                "hhw_supply_temp":
                self.system_parameters.get_param_by_building_id(
                    self.building_id,
                    "load_model_parameters.rc.temp_hw_supply") + 273.15,
                "hhw_return_temp":
                self.system_parameters.get_param_by_building_id(
                    self.building_id,
                    "load_model_parameters.rc.temp_hw_return") + 273.15,
                "temp_setpoint_heating":
                self.system_parameters.get_param_by_building_id(
                    self.building_id,
                    "load_model_parameters.rc.temp_setpoint_heating") + 273.15,
                "temp_setpoint_cooling":
                self.system_parameters.get_param_by_building_id(
                    self.building_id,
                    "load_model_parameters.rc.temp_setpoint_cooling") + 273.15
            }
        }

        # merge ets template values from load_base.py into the building nominal values
        # If there is no ets defined in sys-param file, use the building template data alone
        try:
            nominal_values = {
                **building_template_data['nominal_values'],
                **self.ets_template_data
            }
            combined_template_data = {
                **building_template_data,
                **nominal_values
            }
        except AttributeError:
            combined_template_data = building_template_data

        self.run_template(teaser_building,
                          os.path.join(b_modelica_path.files_dir,
                                       "building.mo"),
                          project_name=scaffold.project_name,
                          model_name=self.building_name,
                          data=combined_template_data)

        self.run_template(teaser_coupling,
                          os.path.join(
                              os.path.join(b_modelica_path.files_dir,
                                           "coupling.mo")),
                          project_name=scaffold.project_name,
                          model_name=self.building_name,
                          data=combined_template_data)

        full_model_name = os.path.join(scaffold.project_name,
                                       scaffold.loads_path.files_relative_dir,
                                       self.building_name,
                                       "coupling").replace(os.path.sep, '.')

        self.run_template(
            run_coupling_template,
            os.path.join(
                os.path.join(b_modelica_path.scripts_dir,
                             "RunTeaserCouplingBuilding.mos")),
            full_model_name=full_model_name,
            model_name="coupling",
        )

        # copy over the required mo files and add the other models to the package order
        mo_files = self.copy_required_mo_files(
            b_modelica_path.files_dir, within=f'{scaffold.project_name}.Loads')
        for f in mo_files:
            package.add_model(os.path.splitext(os.path.basename(f))[0])
        package.add_model('building')
        package.add_model('coupling')

        # save the updated package.mo and package.order in the Loads.B{} folder
        new_package = PackageParser.new_from_template(
            package.path,
            self.building_name,
            package.order,
            within=f"{scaffold.project_name}.Loads")
        new_package.save()
        # AA added this 9/24
        if os.path.exists(
                building_template_data["mos_weather"]["mos_weather_filename"]):
            shutil.copy(
                building_template_data["mos_weather"]["mos_weather_filename"],
                os.path.join(
                    b_modelica_path.resources_dir,
                    building_template_data["mos_weather"]["filename"]))
        else:
            raise Exception(
                f"Missing MOS weather file for Spawn: {building_template_data['mos_weather']['mos_weather_filename']}"
            )
        # end of what AA added 9/24

        # remaining clean up tasks across the entire exported project
        if not keep_original_models:
            shutil.rmtree(
                os.path.join(scaffold.loads_path.files_dir, "Project"))

        # now create the Loads level package and package.order.
        if not os.path.exists(
                os.path.join(scaffold.loads_path.files_dir, 'package.mo')):
            load_package = PackageParser.new_from_template(
                scaffold.loads_path.files_dir,
                "Loads", [self.building_name],
                within=f"{scaffold.project_name}")
            load_package.save()
        else:
            load_package = PackageParser(
                os.path.join(scaffold.loads_path.files_dir))
            load_package.add_model(self.building_name)
            load_package.save()

        # now create the Package level package. This really needs to happen at the GeoJSON to modelica stage, but
        # do it here for now to aid in testing.
        package = PackageParser(scaffold.project_path)
        if 'Loads' not in package.order:
            package.add_model('Loads')
            package.save()
    def to_modelica(self, scaffold):
        """
        Create timeSeries models based on the data in the buildings and geojsons

        :param scaffold: Scaffold object, Scaffold of the entire directory of the project.
        """
        if self.chp_installed:
            template_data = {
                "nominal_values": {
                    "heat_flow_nominal":
                    self.system_parameters.get_param(
                        "$.district_system.default.central_heating_plant_parameters.heat_flow_nominal"
                    ),
                    "mass_hhw_flow_nominal":
                    self.system_parameters.get_param(
                        "$.district_system.default.central_heating_plant_parameters.mass_hhw_flow_nominal"
                    ),
                    "boiler_water_flow_minimum":
                    self.system_parameters.get_param(
                        "$.district_system.default.central_heating_plant_parameters.boiler_water_flow_minimum"
                    ),
                    "pressure_drop_hhw_nominal":
                    self.system_parameters.get_param(
                        "$.district_system.default.central_heating_plant_parameters.pressure_drop_hhw_nominal"
                    ),
                    "pressure_drop_setpoint":
                    self.system_parameters.get_param(
                        "$.district_system.default.central_heating_plant_parameters.pressure_drop_setpoint"
                    ),
                    "temp_setpoint_hhw":
                    self.system_parameters.get_param(
                        "$.district_system.default.central_heating_plant_parameters.temp_setpoint_hhw"
                    ) + 273.15,
                    "pressure_drop_hhw_valve_nominal":
                    self.system_parameters.get_param(
                        "$.district_system.default.central_heating_plant_parameters.pressure_drop_hhw_valve_nominal"
                    ),
                },
                "signals": {
                    "thermal_following":
                    str(
                        self.system_parameters.get_param(
                            "$.district_system.default.central_heating_plant_parameters.chp_thermal_following"
                        )).
                    lower(
                    ),  # Booleans in Python start with a capital letter. Modelica wants it lowercase, hence this.
                },
            }
            plant_template = self.template_env.get_template(
                "HeatingPlantWithCHP.mot")
            self.run_template(
                template=plant_template,
                save_file_name=Path(scaffold.plants_path.files_dir) /
                "CentralHeatingPlant.mo",
                project_name=scaffold.project_name,
                data=template_data)

        self.copy_required_mo_files(dest_folder=scaffold.plants_path.files_dir,
                                    within=f'{scaffold.project_name}.Plants')

        package = PackageParser(scaffold.project_path)
        if 'Plants' not in package.order:
            package.add_model('Plants')
            package.save()

        package_models = ['CentralHeatingPlant'
                          ] + [Path(mo).stem for mo in self.required_mo_files]
        plants_package = PackageParser(scaffold.plants_path.files_dir)
        if plants_package.order_data is None:
            plants_package = PackageParser.new_from_template(
                path=scaffold.plants_path.files_dir,
                name="Plants",
                order=package_models,
                within=scaffold.project_name)
        else:
            for model_name in package_models:
                plants_package.add_model(model_name)
        plants_package.save()
    def to_modelica(self, scaffold):
        """
        Create timeSeries models based on the data in the buildings and geojsons

        :param scaffold: Scaffold object, Scaffold of the entire directory of the project.
        """
        mos_wet_bulb_filename = self.system_parameters.get_param(
            "$.district_system.default.central_cooling_plant_parameters.mos_wet_bulb_filename"
        )

        if mos_wet_bulb_filename is None:
            raise FileNotFoundError(
                'Cooling plant\'s mos_wet_bulb_filename was not provided')

        template_data = {
            "nominal_values": {
                "delta_temp":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.cooling_tower_water_temperature_difference_nominal"
                ),
                "fan_power":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.cooling_tower_fan_power_nominal"
                ),
                "chilled_water_pump_pressure_head":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.chw_pump_head"
                ),
                "condenser_water_pump_pressure_head":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.cw_pump_head"
                ),
                "heat_flow_nominal":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.heat_flow_nominal"
                ),
                "mass_chw_flow_nominal":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.mass_chw_flow_nominal"
                ),
                "mass_cw_flow_nominal":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.mass_cw_flow_nominal"
                ),
                "chiller_water_flow_minimum":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.chiller_water_flow_minimum"
                ),
                "pressure_drop_chw_nominal":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.pressure_drop_chw_nominal"
                ),
                "pressure_drop_cw_nominal":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.pressure_drop_cw_nominal"
                ),
                "pressure_drop_setpoint":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.pressure_drop_setpoint"
                ),
                "temp_setpoint_chw":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.temp_setpoint_chw"
                ),
                "pressure_drop_chw_valve_nominal":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.pressure_drop_chw_valve_nominal"
                ),
                "pressure_drop_cw_pum_nominal":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.pressure_drop_cw_pum_nominal"
                ),
                "temp_air_wb_nominal":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.temp_air_wb_nominal"
                ),
                "temp_cw_in_nominal":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.temp_cw_in_nominal"
                ),
                "delta_temp_approach":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.delta_temp_approach"
                ),
                "ratio_water_air_nominal":
                self.system_parameters.get_param(
                    "$.district_system.default.central_cooling_plant_parameters.ratio_water_air_nominal"
                ),
            },
            "wet_bulb_calc": {
                "mos_wet_bulb_filename": mos_wet_bulb_filename,
                "filename": Path(mos_wet_bulb_filename).name,
                "path": Path(mos_wet_bulb_filename).parent,
                "modelica_path": self.modelica_path(mos_wet_bulb_filename),
            },
        }

        plant_template = self.template_env.get_template(
            "CentralCoolingPlant.mot")
        self.run_template(plant_template,
                          os.path.join(scaffold.plants_path.files_dir,
                                       "CentralCoolingPlant.mo"),
                          project_name=scaffold.project_name,
                          data=template_data)

        self.copy_required_mo_files(dest_folder=scaffold.plants_path.files_dir,
                                    within=f'{scaffold.project_name}.Plants')

        package = PackageParser(scaffold.project_path)
        if 'Plants' not in package.order:
            package.add_model('Plants')
            package.save()

        package_models = ['CentralCoolingPlant'
                          ] + [Path(mo).stem for mo in self.required_mo_files]
        plants_package = PackageParser(scaffold.plants_path.files_dir)
        if plants_package.order_data is None:
            plants_package = PackageParser.new_from_template(
                path=scaffold.plants_path.files_dir,
                name="Plants",
                order=package_models,
                within=scaffold.project_name)
        else:
            for model_name in package_models:
                plants_package.add_model(model_name)
        plants_package.save()
Esempio n. 6
0
    def to_modelica(self):
        """Generate modelica files for the models as well as the modelica file for
        the entire district system.
        """
        # scaffold the project
        self._scaffold.create()
        self.district_model_filepath = Path(
            self._scaffold.districts_path.files_dir
        ) / 'DistrictEnergySystem.mo'

        # create the root package
        root_package = PackageParser.new_from_template(
            self._scaffold.project_path, self._scaffold.project_name, order=[])
        root_package.save()

        # generate model modelica files
        for model in self._coupling_graph.models:
            model.to_modelica(self._scaffold)

        # construct graph of visual components
        diagram = Diagram(self._coupling_graph)

        district_template_params = {
            "district_within_path":
            '.'.join([self._scaffold.project_name, 'Districts']),
            "diagram":
            diagram,
            "couplings": [],
            "models": []
        }
        common_template_params = {
            'globals': {
                'medium_w': 'MediumW',
                'delChiWatTemBui': 'delChiWatTemBui',
                'delChiWatTemDis': 'delChiWatTemDis',
                'delHeaWatTemBui': 'delHeaWatTemBui',
                'delHeaWatTemDis': 'delHeaWatTemDis',
            },
            'graph': self._coupling_graph,
            'sys_params': {
                'district_system':
                self.system_parameters.get_param('$.district_system')
            }
        }
        # render each coupling
        for coupling in self._coupling_graph.couplings:
            template_context = {
                'diagram': diagram.to_dict(coupling.id, is_coupling=True),
            }
            template_context.update(**common_template_params)

            coupling_load = coupling.get_load()
            if coupling_load is not None:
                building_sys_params = self.system_parameters.get_param_by_building_id(
                    coupling_load.building_id, '$')
                template_context['sys_params'][
                    'building'] = building_sys_params

            templated_result = coupling.render_templates(template_context)
            district_template_params['couplings'].append({
                'id':
                coupling.id,
                'component_definitions':
                templated_result['component_definitions'],
                'connect_statements':
                templated_result['connect_statements'],
                'coupling_definitions_template_path':
                templated_result['component_definitions_template_path'],
                'connect_statements_template_path':
                templated_result['connect_statements_template_path'],
            })

        # render each model instance
        for model in self._coupling_graph.models:
            template_params = {
                'model': model.to_dict(self._scaffold),
                'couplings': self._coupling_graph.couplings_by_type(model.id),
                'diagram': diagram.to_dict(model.id, is_coupling=False),
            }
            template_params.update(**common_template_params)

            if issubclass(type(model), LoadBase):
                building_sys_params = self.system_parameters.get_param_by_building_id(
                    model.building_id, '$')
                template_params['sys_params']['building'] = building_sys_params

            templated_instance, instance_template_path = model.render_instance(
                template_params)
            district_template_params['models'].append({
                'id':
                model.id,
                'instance_template_path':
                instance_template_path,
                'instance':
                templated_instance
            })

        # render the full district file
        final_result = render_template('DistrictEnergySystem.mot',
                                       district_template_params)
        with open(self.district_model_filepath, 'w') as f:
            f.write(final_result)

        districts_package = PackageParser.new_from_template(
            self._scaffold.districts_path.files_dir,
            "Districts", ['DistrictEnergySystem'],
            within=f"{self._scaffold.project_name}")
        districts_package.save()
        root_package = PackageParser(self._scaffold.project_path)
        root_package.add_model('Districts')
        root_package.save()