Skip to content

Python scripts

Here are some Python scripts which have been used for processing CityGML files, either independently from SimStadt or before launching SimStadt.

Make backups!

Feel free to use those scripts, but please be sure to have backups of your data before trying them.

Install Python

If Python is not installed yet on your computer, one easy (but heavyweight) way to install Python and many libraries is to install Anaconda. A more lightweight alternative is to install Miniconda, followed by required packages (pip install lxml pandas numpy).

Text editors and IDE

In order to edit and run Python code, you can use a text editor or an IDE. Some examples are:

Add attributes to CityGML buildings

Theory

A CityGML can have a correct geometry and be correctly georeferenced, but could still be missing information required for some workflows (e.g. Heat Demand Analysis).

CityGML files are plain text files, so they can be edited in a text editor (e.g. NotePad++).

<?xml version='1.0' encoding='UTF-8'?>
<CityModel xmlns:xal="urn:oasis...>
  <gml:boundedBy>
    <gml:Envelope srsName="EPSG:31467" srsDimension="3">
      <gml:lowerCorner>3515844.0567215136 5415761.814591559 0.0</gml:lowerCorner>
      <gml:upperCorner>3515946.174771333 5415791.804448826 0.0</gml:upperCorner>
    </gml:Envelope>
  </gml:boundedBy>
  <cityObjectMember>
    <bldg:Building gml:id="DEBW_LOD2_2960">
      <gml:boundedBy>
        <gml:Envelope srsName="urn:ogc:def:crs,crs:EPSG:6.12:31467,crs:EPSG:6.12:5783" srsDimension="3">
          <gml:lowerCorner>3515924.97 5415765.1 284.38</gml:lowerCorner>
          <gml:upperCorner>3515940.92 5415776.11 298.25</gml:upperCorner>
        </gml:Envelope>
      </gml:boundedBy>
      ...

It might not be very convenient to do so, though.

inject_citygml_attributes.py

In order to add missing attributes (e.g. yearOfConstruction or buildingFunction), inject_citygml_attributes.py can be used.

This script requires lxml, pandas and numpy.

usage: inject_citygml_attributes.py [-h] [input_folder] [output_folder]

Inject building attributes or generic attributes into CityGML files.
Each CityGML file inside input_folder should have a corresponding spreadsheet,
with the same filename as the CityGML but a different extension. (e.g. test.csv for test.gml).
If no spreadsheet is present, a CSV template will be automatically written, with the corresponding columns.
Supported formats : ['.xls', '.xlsx', '.ods', '.csv'].

positional arguments:
  input_folder   Input folder, containing CityGML files and their corresponding spreadsheets. (default: input)
  output_folder  Output folder, in which the modified CityGML will be written. (default: output)

optional arguments:
  -h, --help     show this help message and exit
  • Download the script
  • Create an input folder
  • Move the CityGML (e.g. test.gml) inside input folder
  • Run the script with python inject_citygml_attributes.py
  • It outputs:

    INFO: # Parsing every gml file inside 'input'
    WARNING: No spreadsheet (.xls, .xlsx, .ods, .csv) has been found for input/test.gml
    WARNING: input/test.csv has been written as template.
    INFO: Finished all gml files in 0.00 s.
    

  • test.csv has been written inside input folder:

    BuildingID;yearOfConstruction;function;comment
    attribute_type;bldg;bldg;gen
    building123456789;1234;1010;Fake building
    DEBW_LOD2_2960
    DEBW_LOD2_2869
    

  • You can modify it, e.g. either in a text editor or in LibreOffice Calc:

    BuildingID;yearOfConstruction;function;comment
    attribute_type;bldg;bldg;gen
    DEBW_LOD2_2960;1978;1010;Some old residential building
    DEBW_LOD2_2869;2017;2020;Recent office building
    
    which looks like this in a spreadsheet editor:

BuildingID yearOfConstruction function comment
attribute_type bldg bldg gen
DEBW_LOD2_2960 1978 1010 Some old residential building
DEBW_LOD2_2869 2017 2020 Recent office building
  • You can add columns if desired. Building (bldg) and generic (gen) attributes are supported.

  • If you run the script again:

    INFO: # Parsing every gml file inside 'input'
    INFO: ## Processing file input/test.gml...
    INFO:   Processed 3 buildings.
    INFO:   Finished writing output/test.gml.
    INFO: Finished all gml files in 0.02 s.
    

  • A modified CityGML model has been written in output:

    ...
        </gml:boundedBy>
        <cityObjectMember>
          <bldg:Building gml:id="DEBW_LOD2_2960">
    +       <gen:stringAttribute name="comment">
    +         <gen:value>Some old residential building</gen:value>
    +       </gen:stringAttribute>
            <gml:boundedBy>
              <gml:Envelope srsName="urn:ogc:def:crs,crs:EPSG:6.12:31467,crs:EPSG:6.12:5783" srsDimension="3">
                <gml:lowerCorner>3515924.97 5415765.1 284.38</gml:lowerCorner>
    ...
            <energy:physicsProperties>
              <energy:yearOfRefurbishment/>
            </energy:physicsProperties>
    +       <bldg:yearOfConstruction>1978</bldg:yearOfConstruction>
    +       <bldg:function>1010</bldg:function>
          </bldg:Building>
        </cityObjectMember>
        <cityObjectMember>
          <bldg:Building gml:id="DEBW_LOD2_2869">
    +       <gen:stringAttribute name="comment">
    +         <gen:value>Recent office building</gen:value>
    +       </gen:stringAttribute>
            <gml:boundedBy>
              <gml:Envelope srsName="urn:ogc:def:crs,crs:EPSG:6.12:31467,crs:EPSG:6.12:5783" srsDimension="3">
                <gml:lowerCorner>3515848.53 5415767.63999609 284.8071</gml:lowerCorner>
    ...
            <energy:physicsProperties>
              <energy:yearOfRefurbishment/>
            </energy:physicsProperties>
    +       <bldg:yearOfConstruction>2017</bldg:yearOfConstruction>
    +       <bldg:function>2020</bldg:function>
          </bldg:Building>
        </cityObjectMember>
      </CityModel>
    

  • This CityGML model now has enough data for Heat Demand Analysis!

other input & output folders

You can also specify the input and output folders:

python inject_citygml_attributes.py path/to/folder/with/citygmls some/output/folder

Give unique building IDs

After merging two CityGML files, some buildings might share the same ID.

citygml_give_unique_building_ids.py gives them unique IDs (e.g. Building A and Building A_2)

usage: citygml_give_unique_building_ids.py [-h]
                                           citygml_filename
                                           [citygml_filename ...]

Process CityGML files and give unique building IDs if needed.

positional arguments:
  citygml_filename

optional arguments:
  -h, --help        show this help message and exit

List Building IDs and Addresses

It might be useful to get a table of buildings IDs and addresses, directly from the CityGML file.

This script requires lxml.

list_building_ids_and_addresses.py

usage: list_building_ids_and_addresses.py [-h] [file_or_folder]

Parses a CityGML file, lists Building IDs and Addresses if available, and writes a CSV file along the CityGML.

positional arguments:
  file_or_folder  Path to citygml file, or path to folder containing multiple citygml files. Defaults to "input" folder.

optional arguments:
  -h, --help      show this help message and exit
python list_building_ids_and_addresses.py Gruenbuehl_LOD2_ALKIS_1010.gml
Extracting addresses from Gruenbuehl_LOD2_ALKIS_1010.gml...
  Gruenbuehl_LOD2_ALKIS_1010_addresses.csv has been written (with 176 addresses).

Here's a CSV example:

DEBW_51545799724;Deutschland,Ludwigsburg,123,Musterstraße
DEBW_51545797352;Deutschland,Ludwigsburg,234,Musterstraße
DEBW_51545798743;Deutschland,Ludwigsburg,456,Musterstraße
Other attributes

This script could be modified in order to output other attributes.

Run SimStadt workflows

It's possible to run SimStadt without graphical interface, directly from the command line.

run_simstadt_workflow.py can be used in order to automate the process further. Script will probably need to be tailored before it can run.