plugins_manager.cpp 13.6 KB
Newer Older
1
#include "plugins_manager.h"
2 3
#include "rational_function.h"
#include "vertical_segment.h"
4

5
/*
6
#include <QCoreApplication>
7
#include <QDir>
8
*/
9

pacanows's avatar
pacanows committed
10
#ifdef _WIN32
11
    #include <windows.h>
12 13 14
#else
    #include <dlfcn.h>
#endif
15
#include <stdio.h>
16 17 18 19 20 21

//! \brief Open a dynamic library file (.so or .dll) and extract the associated
//! provide function. The template argument is used to cast the library to a
//! specific type.
template<typename T> T open_library(const std::string& filename, const char* function)
{
pacanows's avatar
pacanows committed
22
#ifdef _WIN32
23
    HINSTANCE handle = LoadLibraryA(filename.c_str());
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
    if(handle != NULL)
    {
        T res = (T)GetProcAddress(handle, function);

        if(res == NULL)
        {
            std::cerr << "<<ERROR>> unable to load the symbol \"" << function << "\" from " << filename << std::endl;
            return NULL;
        }
#ifdef DEBUG_CORE
        std::cout << "<<DEBUG>> will provide a " << function << " for library \"" << filename << "\"" << std::endl;
#endif
        return res;
    }
    else
    {
        std::cerr << "<<ERROR>> unable to load the dynamic library file \"" << filename << "\"" << std::endl;
        std::cerr << "          cause: \"" << GetLastError() << "\"" << std::endl;
        return NULL;
    }
44
#else
45 46 47
    void* handle = dlopen(filename.c_str(), RTLD_GLOBAL | RTLD_LAZY);
    
	 if(handle != NULL)
48 49 50
	 {
		 void (*res)();
		 *(void **)(&res) = dlsym(handle, function);
51 52 53 54 55 56 57 58 59 60 61 62 63 64

        if(dlerror() != NULL)
        {
            std::cerr << "<<ERROR>> unable to load the symbol \"" << function << "\" from " << filename << std::endl;
            return NULL;
        }
#ifdef DEBUG_CORE
        std::cout << "<<DEBUG>> will provide a " << function << " for library \"" << filename << "\"" << std::endl;
#endif
        return (T)res;
    }
    else
    {
        std::cerr << "<<ERROR>> unable to load the dynamic library file \"" << filename << "\"" << std::endl;
65
		  std::cerr << "          cause: \"" << dlerror() << "\"" << std::endl;
66 67 68 69 70 71 72
        return NULL;
    }
#endif
}


// Create the object, parse the argument and load all the plugins
73
plugins_manager::plugins_manager(const arguments&) 
74
{
75
/*
76 77 78 79 80 81 82 83 84
	QDir pluginsDir;
	if(args.is_defined("plugins"))
	{
		pluginsDir = QDir(args["plugins"].c_str()) ;
	}
	else if(QCoreApplication::instance() != NULL)
	{
		pluginsDir = QDir(QCoreApplication::instance()->applicationDirPath());
	}
85
	*/
86

87
	/*
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
	foreach (QString fileName, pluginsDir.entryList(QDir::Files)) 
	{
		QPluginLoader loader ;
		loader.setLoadHints(QLibrary::ExportExternalSymbolsHint) ;
		loader.setFileName(pluginsDir.absoluteFilePath(fileName));
		
		// Convert filename for outputing		
		std::string filename(fileName.toStdString()) ;

		if(!loader.load())
		{
#ifdef DEBUG
			std::cout << "<<DEBUG>> " << loader.errorString().toStdString() << std::endl ;
#endif
			continue ;
		}

		QObject *plugin = loader.instance();
		if (plugin != NULL) 
		{
#ifdef DEBUG
			std::cout << "<<DEBUG>> loading plugin " << filename << std::endl ;
#endif
			if(dynamic_cast<function*>(plugin) != NULL)
			{
#ifdef DEBUG
				std::cout << "<<DEBUG>>  -> it is a function" << std::endl ;
#endif
				_functions.insert(std::pair<std::string, function*>(filename, dynamic_cast<function*>(plugin))) ;
			}
			
			if(dynamic_cast<data*>(plugin) != NULL)
			{
#ifdef DEBUG
				std::cout << "<<DEBUG>>  -> it is a data loader" << std::endl ;
#endif
				_datas.insert(std::pair<std::string, data*>(filename, dynamic_cast<data*>(plugin))) ;
			}
			if(dynamic_cast<fitter*>(plugin) != NULL)
			{
#ifdef DEBUG
				std::cout << "<<DEBUG>>  -> it is a fitter" << std::endl ;
#endif
				_fitters.insert(std::pair<std::string, fitter*>(filename, dynamic_cast<fitter*>(plugin))) ;
			}
		}
		else
		{
#ifdef DEBUG
			std::cout << "<<DEBUG>> " << loader.errorString().toStdString() << std::endl ;
#endif
		}
	}
141
	*/
142 143 144 145 146
}

// Get instances of the function, the data and the
// fitter
//
147
function* plugins_manager::get_function()
148
{
149 150 151 152
#ifdef USING_STATIC
    return new rational_function() ;
#else
    if(_functions.empty())
153
	{
154
		return new rational_function() ;
155 156 157 158 159
	}
	else
	{
		return _functions.begin()->second ;
	}
160 161
#endif

162
}
163
data* plugins_manager::get_data()
164
{
Laurent Belcour's avatar
Laurent Belcour committed
165
	//if(_datas.empty())
166
	{
167 168 169
#ifdef DEBUG
        std::cout << "<<DEBUG>>  using vertical segment data loader" << std::endl ;
#endif
170
		return new vertical_segment() ;
Laurent Belcour's avatar
Laurent Belcour committed
171
	}/*
172 173
	else
	{
174
#ifdef DEBUG
175
		std::cout << "<<DEBUG>>  using \"" << _datas.begin()->first << "\" data loader" << std::endl ;
176
#endif
177
		return _datas.begin()->second ;
Laurent Belcour's avatar
Laurent Belcour committed
178
	}*/
179
}
180
fitter* plugins_manager::get_fitter()
181
{
182 183 184
#ifdef USING_STATIC
    return NULL;
#else
185 186 187 188 189 190
	if(_fitters.empty())
	{
		return NULL ;
	}
	else
	{
191
#ifdef DEBUG
192
		std::cout << "<<DEBUG>>  using \"" <<  _fitters.begin()->first << "\"" << std::endl ;
193
#endif
194 195
		return _fitters.begin()->second ;
	}
196
#endif
197 198
}

199 200 201 202 203 204 205 206 207 208

		
//! \brief load a function from the ALTA input file.
function* plugins_manager::get_function(const std::string& filename)
{
	std::ifstream file;
	file.open(filename.c_str()) ;
	if(!file.is_open())
	{
		std::cerr << "<<ERROR>> unable to open file \"" << filename << "\"" << std::endl ;
209
		return NULL;
210 211
	}

212 213 214
	// Set the precision of the input
	file.precision(10);

215 216
	// Parameters of the function object
	int nX, nY;
217
	params::input param_in; params::output param_out;
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
	arguments args;

	// Test for the first line of the file. Should be a ALTA FUNC HEADER
	std::string line ;
	std::getline(file, line) ;
	if(line != "#ALTA FUNC HEADER")
	{
		std::cerr << "<<ERROR>> this is not a function file" << std::endl;
	}

	// Parse the header for the function command line and the dimension
	// of the function
	while(line != "#ALTA HEADER END")
	{
		std::getline(file, line) ;
		std::stringstream linestream(line) ;

		linestream.ignore(1) ;

		std::string comment ;
		linestream >> comment ;

		if(comment == std::string("DIM"))
		{
			linestream >> nX >> nY ;
243 244 245 246 247 248 249 250 251 252 253 254 255
		}
		else if(comment == std::string("PARAM_IN"))
		{
			std::string name;
			linestream >> name;
			std::cout << "<<DEBUG>> parsed input parametrization: " << name << std::endl;
			param_in = params::parse_input(name);
		}
		else if(comment == std::string("PARAM_OUT"))
		{
			std::string name;
			linestream >> name;
			param_out = params::parse_output(name);
256 257
		}
		else if(comment == std::string("CMD"))
258
      {
259 260 261 262 263 264 265 266
			args = arguments::create_arguments(line.substr(4, std::string::npos));
		}
	}

	// Create the function from the command line
	function* f = get_function(args);
	f->setDimX(nX);
	f->setDimY(nY);
Laurent Belcour's avatar
Laurent Belcour committed
267 268 269 270
    if(f->input_parametrization() == params::UNKNOWN_INPUT)
    {
        f->setParametrization(param_in);
    }
271
	f->setParametrization(param_out);
272 273

	// Load the function part from the file object
274
    f->load(file);
275 276 277 278

	return f;
}

279 280 281
//! Get an instance of the function selected based on the name <em>n</em>.
//! Return NULL if no one exist.
function* plugins_manager::get_function(const arguments& args)
282
{
283
    if(!args.is_defined("func"))
284 285 286 287 288 289 290
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> no function plugin specified, returning a rational function" << std::endl;
#endif
        return new rational_function();
    }

291 292
    // The function to be returned.
    function* func = NULL;
Laurent Belcour's avatar
Laurent Belcour committed
293

294
    if(args.is_vec("func"))
295
    {
296 297 298 299 300 301 302 303
        std::vector<std::string> args_vec = args.get_vec("func");

        // Treating the case []
        if(args_vec.size() == 0)
        {
            return NULL;
        }

304
        //! create a <em>compound</em> class to store multiple
305
        //! functions in it.
306 307
		  compound_function* compound = new compound_function();
	
308 309 310 311 312 313
          //! For each args_vec element, create a function object and add
          //! it to the compound one.
          for(unsigned int i=0; i<args_vec.size(); ++i)
          {
              std::string n("--func ");
              n.append(args_vec[i]);
314 315 316
#ifdef DEBUG
              std::cout << "<<DEBUG>> load function with args: " << n << std::endl;
#endif
317 318 319 320 321 322 323 324
              arguments temp_args = arguments::create_arguments(n);
              function* f = get_function(temp_args);
              if(dynamic_cast<nonlinear_function*>(f) == NULL)
              {
                  std::cerr << "<<ERROR>> only non-linear function care compatible with a compound" << std::endl;
              }
              else
              {
325
                  compound->push_back(dynamic_cast<nonlinear_function*>(f), temp_args);
326 327
              }
          }
328

329 330
		  //! return the compound class
		  func = compound;
331 332 333
    }
    else
    {
334 335 336 337 338 339
        std::string filename = args["func"];
        FunctionPrototype myFunction = open_library<FunctionPrototype>(filename, "provide_function");
        if(myFunction != NULL)
        {
#ifdef DEBUG
            std::cout << "<<DEBUG>> using function provider in file \"" << filename << "\"" << std::endl;
340
#endif
341
            func =  myFunction();
342 343 344 345 346 347
        }
        else
        {
            std::cerr << "<<ERROR>> no function provider found in file \"" << filename << "\"" << std::endl;
            return new rational_function() ;
        }
348 349
    }

350 351 352
    // Treat the case of the Fresnel
    if(args.is_defined("fresnel"))
    {
353 354 355 356 357 358 359 360
		 // Cast into a non linear function, only those are permitted to use
		 // a Fresnel term.
		 nonlinear_function* nl_func = dynamic_cast<nonlinear_function*>(func);
		 if(nl_func == NULL)
		 {
			 std::cerr << "<<ERROR>> only non-linear function are permitted to use Fresnel" << std::endl;
			 return func;
		 }
361

362
		 std::cout << "<<DEBUG>> multiplying by a Fresnel term" << std::endl;
363

364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
		 std::string n("--func ");
		 if(args.is_vec("fresnel"))
		 {
			 std::string temp = args["fresnel"];
			 n.append(temp.substr(1, temp.size()-2));
		 }
		 else
		 {
			 std::string fname = args["fresnel"];
			 if(fname.empty()) // Nothing to do except print error, no plugin defined
			 {
				 std::cerr << "<<ERROR>> Fresnel plugin not defined" << std::endl;
				 std::cerr << "<<ERROR>> using --fresnel alone is not permitted" << std::endl;
				 return func;
			 }
			 else // Case where the fresnel parameters is only the plugin filename
			 {
				 n.append(fname);
			 }
		 }

385
		 nonlinear_function* func_fres = dynamic_cast<nonlinear_function*>(get_function(arguments::create_arguments(n)));
386 387 388 389 390 391 392 393 394
		 if(func_fres != NULL)
		 {
			return new product_function(nl_func, func_fres);
		 }
		 else
		 {
			 std::cerr << "<<ERROR>> the right part of the product is not a nonlinear function. Will use only the left part." << std::endl;
			 return func;
		 }
395

396
	 }
397
/*
398 399 400 401 402 403 404
	 // Correction of the data by 1/cosine(theta_L)
	 if(args.is_defined("data-correct-cosine"))
	 {
		 nonlinear_function* cosine = new cosine_function();
		 func = new product_function(cosine, dynamic_cast<nonlinear_function*>(func));
	 }
	 // End of correction
405
*/			
406
    return func;
407
}
408
data* plugins_manager::get_data(const std::string& n)
409
{
410 411
    if(n.empty())
    {
412
#ifdef DEBUG
413
        std::cout << "<<DEBUG>> no data plugin specified, returning a vertial_segment loader" << std::endl;
414
#endif
415 416 417
        return new vertical_segment();
    }

418
	 DataPrototype myData = open_library<DataPrototype>(n, "provide_data");
419 420
    if(myData != NULL)
    {
421
#ifdef DEBUG
422 423 424 425 426 427 428 429 430
        std::cout << "<<DEBUG>> using function provider in file \"" << n << "\"" << std::endl;
#endif
        return myData();
    }
    else
    {
        std::cerr << "<<ERROR>> no data provider found in file \"" << n << "\"" << std::endl;
        return new vertical_segment() ;
    }
431
}
432
fitter* plugins_manager::get_fitter(const std::string& n)
433
{
Laurent Belcour's avatar
Laurent Belcour committed
434 435 436 437 438 439 440 441
    if(n.empty())
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> no fitter plugin specified, returning null" << std::endl;
#endif
        return NULL;
    }

442
    FitterPrototype myFitter = open_library<FitterPrototype>(n, "provide_fitter");
Laurent Belcour's avatar
Laurent Belcour committed
443 444 445 446 447 448 449 450 451
    if(myFitter != NULL)
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> using function provider in file \"" << n << "\"" << std::endl;
#endif
        return myFitter();
    }
    else
    {
452 453
        std::cerr << "<<ERROR>> no fitter provider found in file \"" << n << "\"" << std::endl;
        return NULL ;
Laurent Belcour's avatar
Laurent Belcour committed
454
    }
455
}
456

Laurent Belcour's avatar
Laurent Belcour committed
457
void plugins_manager::check_compatibility(data*& d, function*& f,
458
                                          const arguments& args)
Laurent Belcour's avatar
Laurent Belcour committed
459
{
460 461
	if(d->input_parametrization() == params::UNKNOWN_INPUT &&
		f->input_parametrization() == params::UNKNOWN_INPUT)
Laurent Belcour's avatar
Laurent Belcour committed
462
	{
463
		std::cout << "<<WARNING>> both function and data objects have no parametrization" << std::endl;
Laurent Belcour's avatar
Laurent Belcour committed
464 465 466
	}
	else
	{
467 468 469 470 471 472 473 474 475 476
		if(d->input_parametrization() == params::UNKNOWN_INPUT)
		{
			std::cout << "<<WARNING>> unknown parametrization for data" << std::endl;
		}

		if(f->input_parametrization() == params::UNKNOWN_INPUT)
		{
			std::cout << "<<DEBUG>> function will take the parametrization of the data" << std::endl;
			f->setParametrization(d->input_parametrization());
		}
477
		else if(d->input_parametrization() != f->input_parametrization() && args.is_defined("change-param"))
478
		{
479
			std::cout << "<<INFO>> has to change the parametrization of the input data " << params::get_name(d->input_parametrization()) << std::endl;
480
            std::cout << "<<INFO>> to " << params::get_name(f->input_parametrization()) << std::endl;
481 482 483 484 485 486 487
			data_params* dd = new data_params(d, f->input_parametrization());
			d = dd ;
		}
		else
		{
			std::cout << "<<DEBUG>> no change was made to the parametrization" << std::endl;
		}
Laurent Belcour's avatar
Laurent Belcour committed
488 489 490 491
	}

	if(f->dimY() != d->dimY())
	{
Laurent Belcour's avatar
Laurent Belcour committed
492
        f->setDimY(d->dimY());
Laurent Belcour's avatar
Laurent Belcour committed
493 494 495 496 497 498 499 500 501 502 503
	}

	/*
	// Check is the data has to be clusterized
	if(args.is_defined("cluster-dim"))
	{
	clustering* cluster = new clustering(d, args);
	d = cluster;
	}
	*/
}
504 505 506 507
		
// \todo implement the Darwin (MACOS) version.
#ifdef WIN32
#include <windows.h>
508
size_t plugins_manager::get_system_memory()
509 510 511 512 513 514
{
	MEMORYSTATUSEX status;
	status.dwLength = sizeof(status);
	GlobalMemoryStatusEx(&status);
	return status.ullTotalPhys;
}
515 516 517 518 519
#elif __APPLE__
size_t plugins_manager::get_system_memory()
{
	return 0;
}
520 521
#else
#include <unistd.h>
522
size_t plugins_manager::get_system_memory()
523 524 525 526 527 528
{
	long pages = sysconf(_SC_PHYS_PAGES);
	long page_size = sysconf(_SC_PAGE_SIZE);
	return pages * page_size;
}
#endif