plugins_manager.cpp 13.2 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 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 22

//! \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)
{
#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 45 46
#else
    void* handle = dlopen(filename.c_str(), RTLD_LAZY);
    if(handle != NULL)
47 48 49
	 {
		 void (*res)();
		 *(void **)(&res) = dlsym(handle, function);
50 51 52 53 54 55 56 57 58 59 60 61 62 63

        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;
64
		  std::cerr << "          cause: \"" << dlerror() << "\"" << std::endl;
65 66 67 68 69 70 71
        return NULL;
    }
#endif
}


// Create the object, parse the argument and load all the plugins
72
plugins_manager::plugins_manager(const arguments&) 
73
{
74
/*
75 76 77 78 79 80 81 82 83
	QDir pluginsDir;
	if(args.is_defined("plugins"))
	{
		pluginsDir = QDir(args["plugins"].c_str()) ;
	}
	else if(QCoreApplication::instance() != NULL)
	{
		pluginsDir = QDir(QCoreApplication::instance()->applicationDirPath());
	}
84
	*/
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
	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
		}
	}
140
	*/
141 142 143 144 145
}

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

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

198 199 200 201 202 203 204 205 206 207

		
//! \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 ;
208
		return NULL;
209 210
	}

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

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
	// Parameters of the function object
	int nX, nY;
	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) ;
231
		std::cout << line << std::endl;
232 233 234 235 236 237 238 239 240 241
		std::stringstream linestream(line) ;

		linestream.ignore(1) ;

		std::string comment ;
		linestream >> comment ;

		if(comment == std::string("DIM"))
		{
			linestream >> nX >> nY ;
242
			std::cout << "<<DEBUG>> " << nX << " x " << nY << std::endl; 
243 244
		}
		else if(comment == std::string("CMD"))
245
      {
246 247 248 249 250 251 252 253 254 255
			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);

	// Load the function part from the file object
256
    f->load(file);
257 258 259 260

	return f;
}

261 262 263
//! 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)
264
{
265
    if(!args.is_defined("func"))
266 267 268 269 270 271 272
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> no function plugin specified, returning a rational function" << std::endl;
#endif
        return new rational_function();
    }

273 274
    // The function to be returned.
    function* func = NULL;
Laurent Belcour's avatar
Laurent Belcour committed
275

276
    if(args.is_vec("func"))
277
    {
278 279 280 281 282 283 284 285
        std::vector<std::string> args_vec = args.get_vec("func");

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

286
        //! create a <em>compound</em> class to store multiple
287
        //! functions in it.
288 289
		  compound_function* compound = new compound_function();
	
290 291 292 293 294 295
          //! 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]);
296 297 298
#ifdef DEBUG
              std::cout << "<<DEBUG>> load function with args: " << n << std::endl;
#endif
299 300 301 302 303 304 305 306
              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
              {
307
                  compound->push_back(dynamic_cast<nonlinear_function*>(f), temp_args);
308 309
              }
          }
310

311 312
		  //! return the compound class
		  func = compound;
313 314 315
    }
    else
    {
316 317 318 319 320 321
        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;
322
#endif
323
            func =  myFunction();
324 325 326 327 328 329
        }
        else
        {
            std::cerr << "<<ERROR>> no function provider found in file \"" << filename << "\"" << std::endl;
            return new rational_function() ;
        }
330 331
    }

332 333 334
    // Treat the case of the Fresnel
    if(args.is_defined("fresnel"))
    {
335 336 337 338 339 340 341 342
		 // 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;
		 }
343

344
		 std::cout << "<<DEBUG>> multiplying by a Fresnel term" << std::endl;
345

346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
		 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);
			 }
		 }

367
		 nonlinear_function* func_fres = dynamic_cast<nonlinear_function*>(get_function(arguments::create_arguments(n)));
368 369 370 371 372 373 374 375 376
		 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;
		 }
377

378
	 }
379
/*
380 381 382 383 384 385 386
	 // 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
387
*/			
388
    return func;
389
}
390
data* plugins_manager::get_data(const std::string& n)
391
{
392 393
    if(n.empty())
    {
394
#ifdef DEBUG
395
        std::cout << "<<DEBUG>> no data plugin specified, returning a vertial_segment loader" << std::endl;
396
#endif
397 398 399
        return new vertical_segment();
    }

400
	 DataPrototype myData = open_library<DataPrototype>(n, "provide_data");
401 402
    if(myData != NULL)
    {
403
#ifdef DEBUG
404 405 406 407 408 409 410 411 412
        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() ;
    }
413
}
414
fitter* plugins_manager::get_fitter(const std::string& n)
415
{
Laurent Belcour's avatar
Laurent Belcour committed
416 417 418 419 420 421 422 423
    if(n.empty())
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> no fitter plugin specified, returning null" << std::endl;
#endif
        return NULL;
    }

424
    FitterPrototype myFitter = open_library<FitterPrototype>(n, "provide_fitter");
Laurent Belcour's avatar
Laurent Belcour committed
425 426 427 428 429 430 431 432 433
    if(myFitter != NULL)
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> using function provider in file \"" << n << "\"" << std::endl;
#endif
        return myFitter();
    }
    else
    {
434 435
        std::cerr << "<<ERROR>> no fitter provider found in file \"" << n << "\"" << std::endl;
        return NULL ;
Laurent Belcour's avatar
Laurent Belcour committed
436
    }
437
}
438

Laurent Belcour's avatar
Laurent Belcour committed
439
void plugins_manager::check_compatibility(data*& d, function*& f,
440
                                          const arguments& args)
Laurent Belcour's avatar
Laurent Belcour committed
441
{
442 443
	if(d->input_parametrization() == params::UNKNOWN_INPUT &&
		f->input_parametrization() == params::UNKNOWN_INPUT)
Laurent Belcour's avatar
Laurent Belcour committed
444
	{
445
		std::cout << "<<WARNING>> both function and data objects have no parametrization" << std::endl;
Laurent Belcour's avatar
Laurent Belcour committed
446 447 448
	}
	else
	{
449 450 451 452 453 454 455 456 457 458
		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());
		}
459
		else if(d->input_parametrization() != f->input_parametrization() && args.is_defined("change-param"))
460
		{
461
			std::cout << "<<INFO>> has to change the parametrization of the input data " << params::get_name(d->input_parametrization()) << std::endl;
462
            std::cout << "<<INFO>> to " << params::get_name(f->input_parametrization()) << std::endl;
463 464 465 466 467 468 469
			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
470 471 472 473
	}

	if(f->dimY() != d->dimY())
	{
Laurent Belcour's avatar
Laurent Belcour committed
474
        f->setDimY(d->dimY());
Laurent Belcour's avatar
Laurent Belcour committed
475 476 477 478 479 480 481 482 483 484 485
	}

	/*
	// Check is the data has to be clusterized
	if(args.is_defined("cluster-dim"))
	{
	clustering* cluster = new clustering(d, args);
	d = cluster;
	}
	*/
}
486 487 488 489
		
// \todo implement the Darwin (MACOS) version.
#ifdef WIN32
#include <windows.h>
490
size_t plugins_manager::get_system_memory()
491 492 493 494 495 496
{
	MEMORYSTATUSEX status;
	status.dwLength = sizeof(status);
	GlobalMemoryStatusEx(&status);
	return status.ullTotalPhys;
}
497 498 499 500 501
#elif __APPLE__
size_t plugins_manager::get_system_memory()
{
	return 0;
}
502 503
#else
#include <unistd.h>
504
size_t plugins_manager::get_system_memory()
505 506 507 508 509 510
{
	long pages = sysconf(_SC_PHYS_PAGES);
	long page_size = sysconf(_SC_PAGE_SIZE);
	return pages * page_size;
}
#endif