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

rl-institut / multi-vector-simulator / 8870538658

28 Apr 2024 09:31PM UTC coverage: 75.582% (-1.4%) from 76.96%
8870538658

push

github

web-flow
Merge pull request #971 from rl-institut/fix/black-vulnerability

Fix/black vulnerability

26 of 29 new or added lines in 15 files covered. (89.66%)

826 existing lines in 21 files now uncovered.

5977 of 7908 relevant lines covered (75.58%)

0.76 hits per line

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

88.63
/src/multi_vector_simulator/A1_csv_to_json.py
1
"""
2
Module A1 - Csv to json
3
=======================
4

5
Convert csv files to json file as input for the simulation.
6

7
The default input csv files are stored in "/inputs/elements/csv".
8
Otherwise their path is provided by the user.
9

10
The user can change parameters of the simulation of of the energy system in the csv files.
11

12
Storage: The "energyStorage.csv" contains information about all storages.
13
For each storage there needs to be another file named exactly after each storage-column in the
14
"energyStorage.csv" file. For the default file this is "storage_01", "storage_02" etc.
15
Please stick to this convention.
16

17
The function "create_input_json()" reads all csv files that are stored
18
in the given input folder (input_directory) and creates one json input file for mvs_tool.
19

20
Functions of this module (that need to be tested)
21
- read all necessary input files (`REQUIRED_CSV_FILES`) from input folder
22
- display error message if `CSV_FNAME` already in input folder
23
- read all parameters in from csv files
24
- parse parameter that is given as a timeseries with input file name and header
25
- parse parameter that is given as a list
26

27
- check that parameter that is given as a list results and subsequent other parameters to be given
28
  as list e.g. if we have two output flows in conversion assets there should be two efficiencies
29
  to operational costs (this is not implemented in code yet)
30
- only necessary parameters should be transferred to json dict, error message with additonal parameters
31
- parse data from csv according to intended types - string, boolean, float, int, dict, list!
32
"""
33

34
import json
1✔
35
import logging
1✔
36
import os
1✔
37
import warnings
1✔
38
import pandas as pd
1✔
39

40
from multi_vector_simulator.utils.constants import (
1✔
41
    CSV_FNAME,
42
    CSV_SEPARATORS,
43
    REQUIRED_CSV_FILES,
44
    REQUIRED_CSV_PARAMETERS,
45
    SIMULATION_SETTINGS,
46
    ECONOMIC_DATA,
47
    PROJECT_DATA,
48
    CONSTRAINTS,
49
    ENERGY_BUSSES,
50
    ENERGY_CONSUMPTION,
51
    ENERGY_CONVERSION,
52
    ENERGY_PRODUCTION,
53
    ENERGY_PROVIDERS,
54
    STORAGE_FILENAME,
55
    TYPE_BOOL,
56
    TYPE_STR,
57
    TYPE_NONE,
58
    KNOWN_EXTRA_PARAMETERS,
59
    WARNING_TEXT,
60
    REQUIRED_IN_CSV_ELEMENTS,
61
    DEFAULT_VALUE,
62
    HEADER,
63
    FIX_COST,
64
)
65
from multi_vector_simulator.utils.constants_json_strings import (
1✔
66
    LABEL,
67
    SPECIFIC_COSTS_OM,
68
    DEVELOPMENT_COSTS,
69
    SPECIFIC_COSTS,
70
    AGE_INSTALLED,
71
    LIFETIME,
72
    INSTALLED_CAP,
73
    EFFICIENCY,
74
    INPUT_POWER,
75
    OUTPUT_POWER,
76
    C_RATE,
77
    DISPATCH_PRICE,
78
    SOC_INITIAL,
79
    SOC_MAX,
80
    SOC_MIN,
81
    THERM_LOSSES_REL,
82
    THERM_LOSSES_ABS,
83
    STORAGE_CAPACITY,
84
    FILENAME,
85
    UNIT,
86
    VALUE,
87
    ENERGY_STORAGE,
88
)
89

90

91
from multi_vector_simulator.utils.exceptions import (
1✔
92
    MissingParameterError,
93
    CsvParsingError,
94
    WrongStorageColumn,
95
    MissingCsvEndingError,
96
)
97

98

99
def create_input_json(
1✔
100
    input_directory,
101
    pass_back=True,
102
):
103
    """Convert csv files to json file as input for the simulation.
104

105
    Looks at all csv-files in `input_directory` and compile the information they contain
106
    into a json file. The json file is then saved within the `input_directory`
107
    with the filename `CSV_FNAME`.
108
    While reading the csv files, it is checked, whether all required parameters
109
    for each component are provided. Missing parameters will return a warning message.
110

111
    Parameters
112
    ----------
113
    input_directory, str
114
        path of the directory where the input csv files can be found
115
    pass_back, bool, optional
116
        if True the final json dict is returned. Otherwise it is only saved
117
    Returns
118
    -------
119
        None or dict
120
    """
121

122
    logging.info(
1✔
123
        "loading and converting all csv's from %s" % input_directory + " into one json"
124
    )
125

126
    output_filename = os.path.join(input_directory, CSV_FNAME)
1✔
127

128
    if os.path.exists(output_filename):
1✔
129
        raise FileExistsError(
1✔
130
            f"The mvs json config file {CSV_FNAME} already exists in the input "
131
            f"folder {input_directory}. This is likely due to an aborted "
132
            f"previous run. Please make sure no such file is located within "
133
            f"the folder prior to run a new simulation"
134
        )
135

136
    input_json = {}
1✔
137

138
    # Read all csv files from path input directory
139
    list_assets = []
1✔
140
    for f in os.listdir(input_directory):
1✔
141
        filename = str(f[:-4])
1✔
142
        if filename in REQUIRED_CSV_FILES:
1✔
143
            list_assets.append(filename)
1✔
144
            single_dict = create_json_from_csv(input_directory, filename)
1✔
145
            if filename in [PROJECT_DATA, ECONOMIC_DATA, SIMULATION_SETTINGS]:
1✔
146
                # use filename as label
147
                single_dict[filename][LABEL] = filename
1✔
148
            elif filename in [
1✔
149
                ENERGY_BUSSES,
150
                ENERGY_CONSUMPTION,
151
                ENERGY_CONVERSION,
152
                ENERGY_PRODUCTION,
153
                ENERGY_PROVIDERS,
154
                FIX_COST,
155
            ]:
156
                # use column names as labels, replace underscores and capitalize
157
                for key, item in single_dict[filename].items():
1✔
158
                    item[LABEL] = key
1✔
159
            input_json.update(single_dict)
1✔
160
        elif "storage_" in filename:
1✔
161
            list_assets.append(filename)
1✔
162
            # TODO
163
            pass
1✔
164

165
    # check if all required files are available
166
    extra = list(set(list_assets) ^ set(REQUIRED_CSV_FILES))
1✔
167

168
    missing_csv_files = []
1✔
169
    for i in extra:
1✔
170
        if i in REQUIRED_CSV_FILES:
1✔
171
            missing_csv_files.append(i)
1✔
172
        elif "storage_" in i:
1✔
173
            pass
1✔
174
        else:
175
            logging.error(
×
176
                f"File {i}.csv is an unknown filename and will not be processed."
177
            )
178

179
    if len(missing_csv_files) > 0:
1✔
180
        raise FileNotFoundError(
1✔
181
            f"Required input files {missing_csv_files} are missing! Please add them "
182
            f"into {input_directory}. The required files are {REQUIRED_CSV_FILES}"
183
        )
184
    # store generated json file to file in input_directory.
185
    # This json will be used in the simulation.
186
    with open(output_filename, "w") as outfile:
1✔
187
        json.dump(input_json, outfile, skipkeys=True, sort_keys=True, indent=4)
1✔
188
    logging.info(
1✔
189
        f"Json file created successfully from csv's and stored into {output_filename}\n"
190
    )
191
    logging.debug("Json created successfully from csv.")
1✔
192
    if pass_back:
1✔
193
        return outfile.name
1✔
194

195

196
def create_json_from_csv(
1✔
197
    input_directory, filename, parameters=None, asset_is_a_storage=False
198
):
199
    """
200
    One csv file is loaded and it's parameters are checked. The csv file is
201
    then converted to a dictionary; the name of the csv file is used as the
202
    main key of the dictionary. Exceptions are made for the files
203
    ["economic_data", "project", "project_data", "simulation_settings", "constraints"], here
204
    no main key is added. Another exception is made for the file
205
    "energyStorage". When this file is processed, the according "storage"
206
    files (names of the "storage" columns in "energyStorage" are called and
207
    added to the energyStorage Dictionary.
208

209
    Parameters
210
    ----------
211
    input_directory : str
212
        path of the directory where the input csv files can be found
213
    filename : str
214
        name of the input file that is transformed into a json, without
215
        extension
216
    parameters : list
217
        List of parameters names that are required
218

219
    asset_is_a_storage : bool
220
        default value is False. If the function is called by
221
        add_storage_components() the
222
        parameter is set to True
223

224
    Returns
225
    -------
226
    dict
227
        the converted dictionary
228

229
    Notes
230
    -----
231
    Tested with:
232
    - test_default_values_storage_without_thermal_losses()
233
    - test_default_values_storage_with_thermal_losses()
234
    """
235

236
    logging.debug("Loading input data from csv: %s", filename)
1✔
237

238
    parameters = REQUIRED_CSV_PARAMETERS.get(filename, parameters)
1✔
239

240
    if parameters is None:
1✔
241
        raise MissingParameterError(
×
242
            f"No parameters were provided to extract from the file {filename}.csv \n"
243
            f"Please check {input_directory} for correct parameter names."
244
        )
245

246
    # allow different separators for csv files, take the first one which works
247
    seperator_unknown = True
1✔
248

249
    idx = 0
1✔
250
    while seperator_unknown is True and idx < len(CSV_SEPARATORS):
1✔
251

252
        try:
1✔
253
            df = pd.read_csv(
1✔
254
                os.path.join(input_directory, "{}.csv".format(filename)),
255
                sep=CSV_SEPARATORS[idx],
256
                header=0,
257
                index_col=0,
258
                na_filter=False,
259
            )
260

261
            if len(df.columns) > 0:
1✔
262
                seperator_unknown = False
1✔
263
            else:
264
                idx = idx + 1
1✔
265

266
        except pd.errors.ParserError:
1✔
UNCOV
267
            logging.warning(
×
268
                f"The file {filename} is not separated by {CSV_SEPARATORS[idx]} or has a formatting problem somewhere"
269
            )
270
            seperator_unknown = True
×
UNCOV
271
            idx = idx + 1
×
272

273
    if seperator_unknown is True:
1✔
274
        raise CsvParsingError(
1✔
275
            "The csv file {} has a separator for values which is not one of the "
276
            "following: {}. The file was therefore unparsable".format(
277
                os.path.join(input_directory, f"{filename}.csv"), CSV_SEPARATORS
278
            )
279
        )
280

281
    # check for wrong or missing required parameters
282
    missing_parameters = []
1✔
283
    wrong_parameters = []
1✔
284
    if asset_is_a_storage is False:
1✔
285
        extra = list(set(parameters) ^ set(df.index))
1✔
286
        if len(extra) > 0:
1✔
287
            for i in extra:
1✔
288
                if i in parameters:
1✔
289
                    missing_parameters.append(i)
1✔
290
                else:
291
                    if i not in KNOWN_EXTRA_PARAMETERS:
1✔
292
                        wrong_parameters.append(i)
1✔
293

294
    if len(wrong_parameters) > 0:
1✔
295
        parameter_string = ", ".join(map(str, parameters))
1✔
296
        logging.warning(
1✔
297
            f"The parameter {i} in the file "
298
            f"{os.path.join(input_directory,filename)}.csv is not expected. "
299
            f"Expected parameters are: {str(parameter_string)}"
300
        )
301
        # ignore the wrong parameter which is in the csv but not required by the parameters list
302
        df = df.drop(wrong_parameters)
1✔
303

304
    # convert csv to json
305
    single_dict = {}
1✔
306
    asset_name_string = ""
1✔
307
    if len(df.columns) == 1:
1✔
308
        logging.debug(
1✔
309
            "No %s" % filename + " assets are added because all "
310
            "columns of the csv file are empty."
311
        )
312
    df_copy = df.copy()
1✔
313
    for column in df_copy:
1✔
314
        if column != UNIT:
1✔
315
            column_dict = {}
1✔
316
            # the storage columns are checked for the right parameters,
317
            # Nan values that are not needed are deleted
318
            if asset_is_a_storage is True:
1✔
319
                # check if all three columns are available
320
                if len(df_copy.columns) < 4 or len(df_copy.columns) > 4:
1✔
UNCOV
321
                    logging.error(
×
322
                        f"The file {filename}.csv requires "
323
                        f"three columns, you have inserted {len(df_copy.columns)}"
324
                        "columns."
325
                    )
326
                # add column specific parameters
327
                if column == STORAGE_CAPACITY:
1✔
328
                    extra = [
1✔
329
                        SOC_INITIAL,
330
                        SOC_MAX,
331
                        SOC_MIN,
332
                        THERM_LOSSES_REL,
333
                        THERM_LOSSES_ABS,
334
                    ]
335
                elif column == INPUT_POWER or column == OUTPUT_POWER:
1✔
336
                    extra = [C_RATE, DISPATCH_PRICE]
1✔
337
                else:
338
                    raise WrongStorageColumn(
1✔
339
                        f"The column name {column} in The file {filename}.csv"
340
                        " is not valid. Please use the column names: "
341
                        "'storage capacity', 'input power' and "
342
                        "'output power'."
343
                    )
344
                column_parameters = parameters + extra
1✔
345
                # check if required parameters are missing
346
                for i in set(column_parameters) - set(df_copy.index):
1✔
347
                    if i == THERM_LOSSES_REL:
1✔
348
                        logging.debug(
1✔
349
                            f"You are not using the parameter {THERM_LOSSES_REL}, which allows considering relative thermal energy losses (Values: Float). This is an advanced setting that most users can ignore."
350
                        )
351
                        # Set 0 as default parameter for losses in storage capacity
352
                        losses = pd.DataFrame(
1✔
353
                            data={
354
                                "": THERM_LOSSES_REL,
355
                                df_copy.columns[0]: ["factor"],
356
                                df_copy.columns[1]: [0],
357
                            }
358
                        )
359
                        losses = losses.set_index("")
1✔
360
                        # Append missing parameter to dataframe
361
                        df_copy = pd.concat([df_copy, losses])
1✔
362
                    elif i == THERM_LOSSES_ABS:
1✔
363
                        logging.debug(
1✔
364
                            f"You are not using the parameter {THERM_LOSSES_ABS}, which allows considering relative thermal energy losses (Values: Float). This is an advanced setting that most users can ignore."
365
                        )
366
                        # Set 0 as default parameter for losses in storage capacity
367
                        losses = pd.DataFrame(
1✔
368
                            data={
369
                                "": THERM_LOSSES_ABS,
370
                                df_copy.columns[0]: ["kWh"],
371
                                df_copy.columns[1]: [0],
372
                            }
373
                        )
374
                        losses = losses.set_index("")
1✔
375
                        # Append missing parameter to dataframe
376
                        df_copy = pd.concat([df_copy, losses])
1✔
377
                    else:
378
                        raise MissingParameterError(
1✔
379
                            f"In file {filename}.csv the parameter {i}"
380
                            f" in column {column} is missing."
381
                        )
382

383
                for i in df_copy.index:
1✔
384
                    if i not in column_parameters:
1✔
385
                        # check if not required parameters are set to Nan and
386
                        # if not, set them to Nan
387
                        if i not in [
1✔
388
                            C_RATE,
389
                            DISPATCH_PRICE,
390
                            SOC_INITIAL,
391
                            SOC_MAX,
392
                            SOC_MIN,
393
                            THERM_LOSSES_REL,
394
                            THERM_LOSSES_ABS,
395
                        ]:
396
                            logging.warning(
1✔
397
                                f"The storage parameter {i} of the file "
398
                                f"{os.path.join(input_directory,filename)}.csv "
399
                                f"is not recognized. It will not be "
400
                                "considered in the simulation."
401
                            )
402

403
                            df_copy.loc[[i], [column]] = "NaN"
1✔
404

405
                        elif pd.isnull(df_copy.at[i, column]) is False:
1✔
406
                            logging.warning(
1✔
407
                                f"The storage parameter {i} in column "
408
                                f" {column} of the file {filename}.csv should "
409
                                "be set to NaN. It will not be considered in the "
410
                                "simulation"
411
                            )
412
                            df_copy.loc[[i], [column]] = "NaN"
1✔
413
                        else:
414
                            logging.debug(
1✔
415
                                f"In file {filename}.csv the parameter {str(i)}"
416
                                f" in column {column} is NaN. This is correct; "
417
                                f"the parameter will not be considered."
418
                            )
419
                    # check if all other values have a value unequal to Nan
420
                    elif pd.isnull(df_copy.at[i, column]) is True:
1✔
UNCOV
421
                        logging.warning(
×
422
                            f"In file {filename}.csv the parameter {i}"
423
                            f" in column {column} is NaN. Please insert a value "
424
                            "of 0 or int. For this "
425
                            "simulation the value is set to 0 "
426
                            "automatically."
427
                        )
428

UNCOV
429
                        df_copy.loc[[i], [column]] = 0
×
430
                # delete not required rows in column
431
                df = df_copy[df_copy[column].notna()]
1✔
432

433
            for param, row in df.iterrows():
1✔
434
                if param == LABEL:
1✔
435
                    asset_name_string = asset_name_string + row[column] + ", "
1✔
436

437
                # Find type of input value (csv file is read into df as an object)
438
                if isinstance(row[column], str) and (
1✔
439
                    "[" in row[column] or "]" in row[column]
440
                ):
441
                    if "[" not in row[column] or "]" not in row[column]:
1✔
UNCOV
442
                        logging.warning(
×
443
                            f"In file {filename}, asset {column} for parameter {param} either '[' "
444
                            f"or ']' is missing."
445
                        )
446
                    else:
447
                        if "{" in row[column]:
1✔
448
                            # Define parameter as a list, containing a timeseries, eg "[1,{}]"
449
                            value_string = row[column].replace("'", '"')
×
450
                            value_list = json.loads(value_string)
×
UNCOV
451
                            value_list = [str(v) for v in value_list]
×
452
                        else:
453
                            # Define parameter as a list eg "[1,2]"
454
                            value_string = row[column].replace("[", "").replace("]", "")
1✔
455

456
                            # find the separator used for the list amongst the CSV_SEPARATORS
457
                            list_separator = None
1✔
458
                            separator_count = 0
1✔
459
                            for separator in CSV_SEPARATORS:
1✔
460
                                if separator in value_string:
1✔
461
                                    if value_string.count(separator) > separator_count:
1✔
462
                                        if separator_count > 0:
1✔
UNCOV
463
                                            raise ValueError(
×
464
                                                f"The separator of the list for the "
465
                                                f"parameter {param} is not unique"
466
                                            )
467
                                        separator_count = value_string.count(separator)
1✔
468
                                        list_separator = separator
1✔
469

470
                            value_list = value_string.split(list_separator)
1✔
471

472
                        for item in range(0, len(value_list)):
1✔
473
                            column_dict = conversion(
1✔
474
                                value_list[item].strip(),
475
                                column_dict,
476
                                row,
477
                                param=param,
478
                                asset=column,
479
                                filename=filename,
480
                            )
481
                            if row[UNIT] != TYPE_STR:
1✔
482
                                if VALUE in column_dict[param]:
1✔
483
                                    # if wrapped in list is a scalar
484
                                    value_list[item] = column_dict[param][VALUE]
1✔
485
                                else:
486
                                    # if wrapped in list is a dictionary (ie. timeseries)
UNCOV
487
                                    value_list[item] = column_dict[param]
×
488

489
                            else:
490
                                # if wrapped in list is a string
491
                                value_list[item] = column_dict[param]
1✔
492

493
                        if row[UNIT] != TYPE_STR:
1✔
494
                            column_dict.update(
1✔
495
                                {param: {VALUE: value_list, UNIT: row[UNIT]}}
496
                            )
497
                        else:
498
                            column_dict.update({param: value_list})
1✔
499
                        logging.info(
1✔
500
                            f"Parameter {param} of asset {column} is defined as a list."
501
                        )
502
                else:
503
                    column_dict = conversion(
1✔
504
                        row[column],
505
                        column_dict,
506
                        row,
507
                        param=param,
508
                        asset=column,
509
                        filename=filename,
510
                    )
511

512
            single_dict.update({column: column_dict})
1✔
513
            # add exception for energyStorage
514
            if filename == ENERGY_STORAGE:
1✔
515
                storage_file_name = check_storage_file_is_csv(
1✔
516
                    df.loc[STORAGE_FILENAME][column]
517
                )
518
                storage_dict = add_storage_components(
1✔
519
                    storage_file_name,
520
                    input_directory,
521
                    single_dict[column][LABEL],
522
                )
523
                single_dict[column].update(storage_dict)
1✔
524

525
    logging.debug(
1✔
526
        "From file %s following assets are added to the energy system: %s",
527
        filename,
528
        asset_name_string[:-2],
529
    )
530

531
    # add exception for single dicts
532
    if filename in [
1✔
533
        ECONOMIC_DATA,
534
        PROJECT_DATA,
535
        SIMULATION_SETTINGS,
536
        CONSTRAINTS,
537
    ]:
538
        return single_dict
1✔
539
    elif asset_is_a_storage is True:
1✔
540
        return single_dict
1✔
541
    else:
542
        single_dict2 = {}
1✔
543
        single_dict2.update({filename: single_dict})
1✔
544
        return single_dict2
1✔
545

546

547
def check_storage_file_is_csv(storage_file):
1✔
548
    r"""
549
    Checks that the storage file name defined in `energyStorage.csv` has ending `.csv`.
550

551
    Parameters
552
    ----------
553
    storage_file: str
554
        Defined storage file name
555

556
    Returns
557
    -------
558

559
    If test fails: MissingCsvEndingError(ValueError), else:
560

561
    storage_file: str
562
        Storage file name without ending '.csv'
563

564
    """
565
    if storage_file[-4:] == ".csv":
1✔
566
        storage_file = storage_file[:-4]
1✔
567
    else:
568
        raise MissingCsvEndingError(
1✔
569
            f"The storage file defined as input in {ENERGY_STORAGE} does not end with '.csv' but is only {storage_file}. Please add the file ending."
570
        )
571
    return storage_file
1✔
572

573

574
def conversion(value, asset_dict, row, param, asset, filename=""):
1✔
575
    r"""
576
    This function converts the input given in the csv to the dict used in the MVS.
577

578
    When using json files, they are already provided parsed like this functions output.
579

580
    Parameters
581
    ----------
582
    value: Misc.
583
        Value to be parsed
584

585
    asset_dict: dict
586
        Dict of asset that is to be filled with data
587

588
    row:
589
    param: str
590
        Parameter that is currently parsed
591

592
    asset
593
    filename
594

595
    Returns
596
    -------
597
    """
598
    if pd.isnull(value):
1✔
UNCOV
599
        logging.error(
×
600
            f"Parameter {param} of asset {asset} (group: {filename}) is missing. "
601
            f"The simulation may continue, but errors during execution or in the results can be expected."
602
        )
603

604
    if isinstance(value, str) and ("{" in value or "}" in value):
1✔
605
        # if parameter defined as dictionary
606
        # example: input,str,"{'file_name':'pv_gen_merra2_2014_eff1_tilt40_az180.csv','header':'kW','unit':'kW'}"
607
        # todo this would not include [value, dict] eg. for multiple busses with one fix and one timeseries efficiency
608
        if "{" not in value or "}" not in value:
1✔
UNCOV
609
            logging.warning(
×
610
                f"In file {filename}, asset {asset} for parameter {param} either '{{' or '}}' is "
611
                f"missing."
612
            )
613
        else:
614
            dict_string = value.replace("'", '"')
1✔
615
            asset_dict.update({param: json.loads(dict_string)})
1✔
616
            if (
1✔
617
                FILENAME in asset_dict[param]
618
                and HEADER in asset_dict[param]
619
                and UNIT in asset_dict[param]
620
            ):
UNCOV
621
                logging.info(
×
622
                    f"Parameter {param} of asset {asset} is defined as a timeseries."
623
                )
624
            else:
625
                logging.warning(
1✔
626
                    f"Parameter {param} of asset {asset} is defined as a dict, "
627
                    f"bus does not inlude parameters {FILENAME}, {HEADER} and {UNIT} to make the input complete "
628
                    f"and result in a timeseries."
629
                )
630

631
            # todo: this should result in reading the csv and writing a pd.Series to the param
632

633
    # If unit should be a string
634
    elif row[UNIT] == TYPE_STR:
1✔
635
        asset_dict.update({param: value})
1✔
636

637
    else:
638
        # If unit should be a bool
639
        if row[UNIT] == TYPE_BOOL:
1✔
640
            if value in [True, "TRUE", "True", "true", "T", "t", "1"]:
1✔
641
                value = True
1✔
642
            elif value in [False, "FALSE", "False", "false", "F", "f", "0"]:
1✔
643
                value = False
1✔
644
            else:
UNCOV
645
                logging.warning(
×
646
                    f"Parameter {param} of asset {asset} is not a boolean value "
647
                    "(True/T/true or False/F/false)."
648
                )
649
        else:
650
            if value == TYPE_NONE or value is None:
1✔
651
                value = None
1✔
652
            else:
653
                try:
1✔
654
                    value = float(value)
1✔
655
                    if value.is_integer() is True:
1✔
656
                        value = int(value)
1✔
657
                except:
×
658
                    try:
×
659
                        value = int(value)
×
660
                    except:
×
UNCOV
661
                        logging.debug(
×
662
                            f"Of asset {asset} the parameter {param} is defined by {value} of type {type(value)}. This is unexpected-"
663
                        )
664

665
        asset_dict.update({param: {VALUE: value, UNIT: row[UNIT]}})
1✔
666
    return asset_dict
1✔
667

668

669
def add_storage_components(storage_filename, input_directory, storage_label):
1✔
670
    r"""
671
    Creates json dict from storage csv.
672

673
    Loads the csv of a the specific storage listed as column in
674
    "energyStorage.csv", checks for complete set of parameters, adds a label and creates
675
    a json dictionary.
676

677
    Parameters
678
    ----------
679
    storage_filename: str
680
        file name excl. extension, given by the parameter 'file_name` in "energyStorage.csv
681
    input_directory: str
682
        path to the input directory where `storage_filename` is located
683
    storage_label: str
684
        Label of storage
685

686
    Notes
687
    -----
688
    Tested with:
689
    - test_add_storage_components_label_correctly_added()
690

691
    Returns
692
    -------
693
    dict
694
        dictionary containing the storage parameters
695
    """
696
    if not os.path.exists(os.path.join(input_directory, f"{storage_filename}.csv")):
1✔
UNCOV
697
        logging.error(f"The storage file {storage_filename}.csv is missing!")
×
698
    else:
699
        # hardcoded parameter list of common parameters in all columns
700
        parameters = [
1✔
701
            AGE_INSTALLED,
702
            DEVELOPMENT_COSTS,
703
            SPECIFIC_COSTS,
704
            EFFICIENCY,
705
            INSTALLED_CAP,
706
            LIFETIME,
707
            SPECIFIC_COSTS_OM,
708
            UNIT,
709
        ]
710
        single_dict = create_json_from_csv(
1✔
711
            input_directory,
712
            filename=storage_filename,
713
            parameters=parameters,
714
            asset_is_a_storage=True,
715
        )
716
        # add labels to storage
717
        for key, item in single_dict.items():
1✔
718
            item[LABEL] = " ".join([storage_label, key])
1✔
719
        return single_dict
1✔
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

© 2026 Coveralls, Inc