Multi-threaded Outdoor Propagation

Detailed Description

This is an example of how to use the WinProp API for multi-threaded outdoor propagation with OpenMP. The full example is distributed with the installation.
#include <stdio.h>
#include <string>
#include <iostream>

#ifdef _OPENMP
#include <omp.h>
#endif

#include "outdoor_propagation_openmp.h"

#ifndef API_DATA_FOLDER
#define API_DATA_FOLDER "../../api/winprop/data/"
#endif // !API_DATA_FOLDER

int main(int argc, char** argv)
{
	// Load topography and building data once for all computations.
	TOPOGRAPHY TopographyData;
	InterfaceTopoInit(&TopographyData);
	InterfaceLoadTopoASC(&TopographyData, API_DATA_FOLDER "outdoor/Topo.asc");

	URBAN_BUILDINGS BuildingData;
	InterfaceBuildingsInit(&BuildingData);
	InterfaceLoadBuildingsASCII(&BuildingData, API_DATA_FOLDER "outdoor/City.oda");

	// Set the number of parallel threads.
#ifdef _OPENMP
	omp_set_num_threads(4);
#endif

	// As an example we're computing the same antenna location in the same environment with 16
	// different frequencies.
#pragma omp parallel for schedule(dynamic,1)
	for (int i = 0; i < 16; i++)
	{
		int Error = 0;

		WinProp_ParaMain GeneralParameters;

		WinProp_Structure_Init_ParameterMain(&GeneralParameters);

		// Definition of scenario
		/* Definition of general parameters. */
		GeneralParameters.ScenarioMode = SCENARIOMODE_URBAN; // Urban prediction
		GeneralParameters.PredictionModelUrban = PREDMODEL_UDP; // Use Dominant Path Model

		/* Definition of prediction area. */
		GeneralParameters.UrbanLowerLeftX = 100.0;
		GeneralParameters.UrbanLowerLeftY = 100.0;
		GeneralParameters.UrbanUpperRightX = 2200.0;
		GeneralParameters.UrbanUpperRightY = 3200.0;

		/* Copy coordinates to prediction area of second model (not yet used) */
		GeneralParameters.RuralLowerLeftX = GeneralParameters.UrbanLowerLeftX;
		GeneralParameters.RuralLowerLeftY = GeneralParameters.UrbanLowerLeftY;
		GeneralParameters.RuralUpperRightX = GeneralParameters.UrbanUpperRightX;
		GeneralParameters.RuralUpperRightY = GeneralParameters.UrbanUpperRightY;

		double PredictionHeight = 1.5;

		/* Size of matrix with results. */
		GeneralParameters.Resolution = 10.0;                       // Resolution in meter
		GeneralParameters.NrLayers = 1;                            // Number of prediction heights
		GeneralParameters.PredictionHeights = &PredictionHeight;   // Prediction height in meter

		/* Building vector data and topography. */
		GeneralParameters.BuildingsMode = BUILDINGSMODE_RAM;
		GeneralParameters.Buildings = BuildingData;

		/* Topography data */
		GeneralParameters.TopographyMode = TOPOMODE_RAM;
		GeneralParameters.Topography = TopographyData;

		// Callbacks
        WinProp_Callback Callback;
        WinProp_Structure_Init_Callback(&Callback);
		Callback.Percentage = CallbackProgress;
		Callback.Message = CallbackMessage;
		Callback.Error = CallbackError;

		/* Position and configuration. */
		WinProp_Antenna Antenna;
		WinProp_Structure_Init_Antenna(&Antenna);
		Antenna.Id = i + 1;
		Antenna.SiteId = 1;
		Antenna.Longitude_X = 1100.0;
		Antenna.Latitude_Y = 2100.0;
		Antenna.Height = 20.0;
		Antenna.Power = 43.0; // Power in dBm
		Antenna.Frequency = 900.0 + 100. * i; // Frequency in MHz

		char AntennaName[500];
		sprintf(AntennaName, "Antenna %i", i);
		Antenna.Name = AntennaName;

		WinProp_Result Resultmatrix;
		WinProp_RayMatrix RayMatrix;
		WinProp_Structure_Init_Result(&Resultmatrix);
		WinProp_Structure_Init_RayMatrix(&RayMatrix);

		// Compute outdoor prediction
		Error = OutdoorPlugIn_ComputePrediction(
			&Antenna, &GeneralParameters, NULL, 0, NULL, NULL, NULL, NULL, &Callback, &Resultmatrix, &RayMatrix, NULL, NULL);

		// Do something with results
		if (Error == 0)
		{
			char Filename[500];
			sprintf(Filename, API_DATA_FOLDER "output/Results Antenna %i.txt", i);
			write_ascii(&Resultmatrix, Filename);
		}
		else 
		{
			/* Error during prediction. Print error message. */
			CallbackError(GeneralParameters.ErrorMessageMain, Error);
		}

		// Free per thread memory
		WinProp_FreeResult(&Resultmatrix);
		WinProp_FreeRayMatrix(&RayMatrix);
	}

	// Free global memory
	InterfaceTopoFree(&TopographyData);
	InterfaceBuildingsInit(&BuildingData);
	
	return 0;
}

int _STD_CALL CallbackMessage(const char * Text)
{
	if (Text == nullptr)
		return 0;

	std::cout << "\n" << Text;

	return(0);
}

int _STD_CALL CallbackError(const char * Text, int Error)
{
	if (Text == nullptr)
		return 0;

	std::cout << "\n";

#ifdef __LINUX
	std::cout << "\033[31m" << "Error (" << Error << "): "; // highlight error in red color
#else
	HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTextAttribute(hConsole, FOREGROUND_RED);
	std::cout << "Error (" << Error << "): ";
#endif // __LINUX
	std::cout << Text;

#ifdef __LINUX
	std::cout << "\033[0m"; // highlight error in red color
#else
	SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN);
#endif // __LINUX

	return 0;
}

int _STD_CALL CallbackProgress(int value, const char* text)
{
	char Line[200];

	sprintf(Line, "\n%d%% %s", value, text);
	std::cout << Line;

	return(0);
}

void write_ascii(const WinProp_Result* Resultmatrix, const char* Filename) {
	FILE* OutputFile = fopen(Filename,"w");
	if (OutputFile)
	{
		/* Loop all pixels. */
		for (int x = 0; x < Resultmatrix->Columns; x++)
		{
			for (int y = 0; y < Resultmatrix->Lines; y++)
			{
				/* Compute real coordinates. */
				double Coordinate_X = Resultmatrix->LowerLeftX + ((double)x + 0.5) * Resultmatrix->Resolution;
				double Coordinate_Y = Resultmatrix->LowerLeftY + ((double)y + 0.5) * Resultmatrix->Resolution;

				/* Check if pixel was computed or not */
				if (Resultmatrix->Matrix[0][x][y] > -1000)
					fprintf(OutputFile, "%.2f\t%.2f\t%.2f\n", Coordinate_X, Coordinate_Y, Resultmatrix->Matrix[0][x][y]);
			}
		}

		/* Close file. */
		fclose(OutputFile);
	}
	else
		printf("\nCould not open the File: %s for writing.\n",Filename);
}