Demo program

This C demo program illustrates how to use the Meteonorm library.

/**
 * @file demo.c
 * @brief Meteonorm demo program
 *
 * This program demonstrates the usage of the Meteonorm library.
 *
 * Copyright (c) Meteotest AG
 */

#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "meteonorm.h"

// Forward declarations
void compute(mn_input *, mn_frequency);
void compute_imported_monthly();
void print_horizon(double horizon[360]);

#define NUM_LOCATIONS 5
#define NUM_MONTHS 12

typedef struct location {
    char city[50];
    double lat;
    double lon;
    double altitude;
    float horizon[360];
    float ghi[NUM_MONTHS];  // Global Horizontal Irradiance (ghi)
    float ta[NUM_MONTHS];   // Temperature (ta)
    float ff[NUM_MONTHS];   // Wind speed (ff)
} location;

void usage(const char *name) {
    printf("usage: %s --datapath=<path>\n", name);
    exit(1);
}

int main(int argc, char *argv[]) {
    char *datapath = NULL;

    struct option long_options[] = {{"datapath", required_argument, NULL, 'd'}, {NULL, 0, NULL, 0}};

    int opt;
    while ((opt = getopt_long(argc, argv, "d:", long_options, NULL)) != -1) {
        switch (opt) {
            case 'd':
                datapath = optarg;
                break;
            default:
                usage(argv[0]);
        }
    }

    if (!datapath) {
        printf("error: datapath argument not provided\n");
        usage(argv[0]);
    }

    // Initialize Meteonorm library
    char *key = "your-license-key";
    mn_error err = mn_init(key, datapath);
    if (err.status != MN_STATUS_OK) {
        printf("error: failed to initialize Meteonorm: %s\n", err.message);
        return err.status;
    }

    // Retrieve Meteonorm version
    mn_version v = mn_get_version();
    printf("meteonorm version: commit: %s, build date: %s\n", v.commit, v.build_date);

    mn_input *input = mn_input_new();

    // Bern, Switzerland: 46.9480° N, 7.4474° E
    mn_status status = mn_input_set_latitude(input, 46.9480);
    if (status != MN_STATUS_OK) {
        printf("error: failed to set latitude\n");
        return status;
    }
    status = mn_input_set_longitude(input, 7.4474);
    if (status != MN_STATUS_OK) {
        printf("error: failed to set longitude\n");
        return status;
    }
    status = mn_input_set_random_seed(input, 42);
    if (status != MN_STATUS_OK) {
        printf("error: failed to set random seed\n");
        return status;
    }
    status = mn_input_set_surface_tilt(input, 30);
    if (status != MN_STATUS_OK) {
        printf("error: failed to set surface tilt\n");
        return status;
    }
    status = mn_input_set_surface_azimuth(input, 180);
    if (status != MN_STATUS_OK) {
        printf("error: failed to set surface azimuth\n");
        return status;
    }
    status = mn_input_set_situation(input, MN_SITUATION_CITY);
    if (status != MN_STATUS_OK) {
        printf("error: failed to set situation\n");
        return status;
    }

    // Compute TMY (hourly)
    compute(input, MN_FREQUENCY_1_HOUR);

    status = mn_input_set_altitude(input, 551);
    if (status != MN_STATUS_OK) {
        printf("error: failed to set altitude\n");
        return status;
    }
    status = mn_input_set_time_zone(input, 1);
    if (status != MN_STATUS_OK) {
        printf("error: failed to set time zone\n");
        return status;
    }

    // Compute TMY (minute)
    compute(input, MN_FREQUENCY_1_MINUTE);

    mn_input_free(input);

    // Compute TMY based on imported monthly data
    compute_imported_monthly();

    // Look up WMO station
    printf("\nlooking up WMO station...\n");
    mn_wmo_station station = mn_get_wmo_station(67000);
    if (station.error.status != MN_STATUS_OK) {
        printf("error: failed to get WMO station: %s\n", station.error.message);
        return station.error.status;
    }
    printf("station: name: %s, latitude: %f, longitude: %f\n", station.name, station.latitude, station.longitude);

    // Look up geo data
    printf("\nlooking up data of Kathmandu (Nepal)...\n");
    double lat = 27.7103;
    double lon = 85.3222;
    mn_time_zone tz = mn_get_time_zone(lat, lon);  // (UTC +5:45)
    if (tz.error.status != MN_STATUS_OK) {
        printf("error: failed to get time zone: %s\n", tz.error.message);
        return tz.error.status;
    }
    printf("time zone: offset: %f\n", tz.offset);

    mn_altitude altitude = mn_get_altitude(lat, lon);
    if (altitude.error.status != MN_STATUS_OK) {
        printf("error: failed to get altitude: %s\n", altitude.error.message);
        return altitude.error.status;
    }
    printf("altitude: %f\n", altitude.elevation);

    mn_horizon h = mn_get_horizon(lat, lon);
    print_horizon(h.horizon);

    // Unix timestamp at Jan 1, 2005 at 00:00
    mn_time t = mn_time_new(2005, 1, 1, 0, 0, 0);
    int64_t twothousandfive = 1104537600;
    if (t != twothousandfive) {
        printf("error: failed to create time: want: %ld: got: %ld\n", twothousandfive, t);
    }

    t = mn_time_new(2010, 1, 1, 0, 0, 0);
    int twothousandten = 1262304000;
    if (t != twothousandten) {
        printf("error: failed to create time: want: %d: got: %ld\n", twothousandten, t);
    }

    // Release Meteonorm library
    mn_deinit();

    return 0;
}

void compute(mn_input *input, mn_frequency freq) {
    printf("\ncomputing %s...\n", freq == MN_FREQUENCY_1_HOUR ? "hourly" : "minute");

    mn_status status = mn_input_set_frequency(input, freq);
    if (status != MN_STATUS_OK) {
        printf("error: failed to set frequency\n");
        return;
    }

    clock_t start = clock();
    mn_result *res = mn_compute(input);
    clock_t end = clock();
    double elapsed = ((double)(end - start)) / CLOCKS_PER_SEC;
    printf("took: %fsec\n", elapsed);

    if (res->error.status != MN_STATUS_OK) {
        printf("error: computation failed: status: %d: message: %s\n", res->error.status, res->error.message);
        mn_result_free(res);
        return;
    }

    printf("altitude: %f\n", res->altitude);
    print_horizon(res->horizon);
    printf("time zone: %f\n", res->time_zone);
    printf("frequency (0: hourly, 1: minute): %d\n", res->frequency);
    printf("start year of irradiance period of nearest station: %d\n",
           res->start_year_of_irradiance_period_of_nearest_station);
    printf("end year of irradiance period of nearest station: %d\n",
           res->end_year_of_irradiance_period_of_nearest_station);
    printf("irradiance station data weight: %f\n", res->irradiance_station_data_weight);
    printf("uncertainty of irradiance estimation: %f\n", res->uncertainty_of_irradiance_estimation);
    printf("uncertainty of temperature estimation: %f\n", res->uncertainty_of_temperature_estimation);
    printf("irradiance year-to-year variability: %f\n", res->irradiance_year_to_year_variability);
    printf("irradiance probability of exceedence p90: %d\n", res->irradiance_yearly_poe90);
    printf("irradiance probability of exceedence p10: %d\n", res->irradiance_yearly_poe10);

    mn_result_free(res);
}

void compute_imported_monthly() {
    location locations[NUM_LOCATIONS] = {
        {
            "Geneva",
            46.2,
            6.15,
            405,
            {
                5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            },
            {34.7, 56.9, 105.8, 145.0, 172.2, 193.0, 196.2, 166.9, 123.2, 74.8, 38.4, 26.3},  // ghi
            {2.2, 2.9, 6.8, 10.9, 14.7, 19.2, 20.8, 20.0, 15.9, 11.6, 6.3, 2.9},              // ta
            {2.3, 2.5, 2.8, 2.6, 2.4, 2.3, 2.2, 1.9, 2.1, 1.9, 2.1, 2.3}                      // ff
        },
        {
            "Munich",
            48.14,
            11.574,
            526,
            {0},
            {31.1, 51.8, 96.9, 134.9, 159.9, 172.4, 171.2, 148.0, 103.5, 66.8, 33.6, 25.6},  // ghi
            {-0.3, 0.7, 4.8, 9.6, 13.8, 17.6, 18.9, 18.5, 13.9, 9.5, 4.4, 1.0},              // ta
            {3.9, 3.8, 4.0, 3.4, 3.3, 2.9, 3.0, 2.7, 2.8, 2.8, 3.3, 3.6}                     // ff
        },
        {
            "Sydney",
            -33.87,
            151.21,
            42,
            {0},
            {206.1, 168.0, 154.0, 125.3, 93.7, 72.0, 80.4, 104.2, 128.9, 165.2, 176.4, 201.6},  // ghi
            {23.2, 23.0, 21.8, 19.1, 15.9, 13.5, 12.9, 14.0, 16.8, 18.7, 20.3, 21.9},           // ta
            {3.6, 3.3, 2.9, 2.5, 2.5, 2.5, 2.6, 2.9, 3.1, 3.3, 3.5, 3.5}                        // ff
        },
        {
            "San Francisco",
            37.77,
            -122.42,
            0,
            {0},
            {65.9, 88.2, 136.2, 170.0, 199.1, 214.6, 221.1, 198.4, 163.6, 116.3, 75.6, 65.5},  // ghi
            {10.5, 11.5, 12.7, 13.5, 15.0, 16.7, 17.3, 17.7, 17.9, 16.3, 13.2, 10.7},          // ta
            {2.8, 3.5, 4.1, 4.9, 5.3, 5.3, 5.0, 4.8, 4.3, 3.6, 2.9, 3.0}                       // ff
        },
        {
            "Beijing",
            39.93,
            116.4,
            30,
            {0},
            {67.8, 84.1, 125.7, 148.2, 173.4, 153.0, 147.5, 142.0, 117.5, 95.8, 67.6, 58.3},  // ghi
            {-3.4, -0.1, 7.4, 15.0, 21.4, 25.1, 27.0, 25.8, 20.8, 13.1, 4.5, -1.8},           // ta
            {3.1, 3.0, 3.3, 3.5, 3.2, 2.6, 2.4, 2.3, 2.3, 2.4, 2.7, 3.1}                      // ff
        }};

    mn_frequency freq = MN_FREQUENCY_1_HOUR;
    for (int i = 0; i < NUM_LOCATIONS; i++) {
        printf("\nimported monthly: %s: computing hourly...\n", locations[i].city);

        mn_input *input = mn_input_new();
        mn_status status = mn_input_set_latitude(input, locations[i].lat);
        if (status != MN_STATUS_OK) {
            printf("imported monthly: %s: failed to set latitude\n", locations[i].city);
            mn_input_free(input);
            continue;
        }
        status = mn_input_set_longitude(input, locations[i].lon);
        if (status != MN_STATUS_OK) {
            printf("imported monthly: %s: failed to set longitude\n", locations[i].city);
            mn_input_free(input);
            continue;
        }

        status = mn_input_set_frequency(input, freq);
        if (status != MN_STATUS_OK) {
            printf("imported monthly: %s: failed to set longitude\n", locations[i].city);
            mn_input_free(input);
            continue;
        }

        status = mn_input_set_altitude(input, locations[i].altitude);
        if (status != MN_STATUS_OK) {
            printf("imported monthly: %s: failed to set altiude\n", locations[i].city);
            mn_input_free(input);
            continue;
        }

        mn_values *horizon = mn_values_new(locations[i].horizon, 360);
        status = mn_input_set_horizon(input, horizon);
        if (status != MN_STATUS_OK) {
            printf("imported monthly: %s: failed to set horizon\n", locations[i].city);
            mn_input_free(input);
            continue;
        }

        mn_values *ghi = mn_values_new(locations[i].ghi, NUM_MONTHS);
        status = mn_input_set_imported_monthly_global_horizontal_irradiance(input, ghi);
        if (status != MN_STATUS_OK) {
            printf("imported monthly: %s: failed to set global irradiance\n", locations[i].city);
            mn_input_free(input);
            continue;
        }

        mn_values *ta = mn_values_new(locations[i].ta, NUM_MONTHS);
        status = mn_input_set_imported_monthly_temperature(input, ta);
        if (status != MN_STATUS_OK) {
            printf("imported monthly: %s: failed to set temperature", locations[i].city);
            mn_input_free(input);
            continue;
        }

        mn_values *ff = mn_values_new(locations[i].ff, NUM_MONTHS);
        status = mn_input_set_imported_monthly_wind_speed(input, ff);
        if (status != MN_STATUS_OK) {
            printf("imported monthly: %s: failed to set wind speed\n", locations[i].city);
            mn_input_free(input);
            continue;
        }

        mn_result *res = mn_compute(input);
        if (res->error.status != MN_STATUS_OK) {
            printf("imported monthly: %s: computation failed: status: %d: message: %s\n", locations[i].city,
                   res->error.status, res->error.message);
            mn_result_free(res);
            mn_input_free(input);
            continue;
        }

        printf("altitude: %f\n", res->altitude);
        print_horizon(res->horizon);

        mn_result_free(res);
        mn_input_free(input);
    }
}

void print_horizon(double horizon[360]) {
    printf("horizon: [");
    for (int i = 0; i < 360; i++) {
        if (i > 0) {
            printf(", ");
        }
        printf("%.0f", horizon[i]);
    }
    printf("]\n");
}
c
Download the demo program