CompositeFunction.cpp 23.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*WIKI*
A composite function is a function containing other functions. It combines the values calculated by the member functions by adding them. The members are indexed from 0 to the number of functions minus 1. The indices are defined by the order in which the functions were added. Composite functions do not have their own parameters, instead they use parameters of the member functions. Parameter names are formed from the member function's index and its parameter name: f[index].[name]. For example, name "f0.Sigma" would be given to the "Sigma" parameter of a Gaussian added first to the composite function. If a member function is a composite function itself the same principle applies: 'f[index].' is prepended to a name, e.g. "f0.f1.Sigma".

The input string to the Fit algorithm for a CompositeFunction is constructed by joining the inputs of the member functions using the semicolon ';' as a separator. For example, the string for two [[Gaussian]]s with tied sigma parameters may look like the following:

 name=Gaussian,PeakCentre=0,Height=1,Sigma=0.1,constraints=(0<Sigma<1);name=Gaussian,PeakCentre=1,Height=1,Sigma=0.1;ties=(f1.Sigma=f0.Sigma)

Note that the ties clause is also separated by a semicolon. It is done because the parameters are from different functions. Ties between parameters of the same function can be placed inside the member definition in which the local parameter names must be used, for example:

 name = FunctionType, P1=0, ties=( P2 = 2*P1 ); name = FunctionType, P1=0, ties=( P2 = 3 )

which is equivalent to

 name = FunctionType, P1=0; name = FunctionType, P1=0; ties=( f0.P2 = 2*f0.P1, f1.P2 = 3 )

Boundary constraints usually make sense to put in a local function definition but they can also be moved to the composite function level, i.e. can be separated by ';'. In this case the full parameter name must be used, for example:

 name=Gaussian,PeakCentre=0,Height=1,Sigma=0.1;name=Gaussian,PeakCentre=1,Height=1,Sigma=0.1;ties=(f1.Sigma=f0.Sigma);constraints=(0<f0.Sigma<1)


Mantid defines a number of fitting functions which extend CompositeFunction. These are functions which also include other functions but use different operations to combine them. Examples are [[ProductFunction]] and [[Convolution]]. Everything said about parameters of the CompositeFunction applies to these functions.

Input strings of an extended composite function must start with "composite=FunctionName;" and followed by the definitions of its members as described for CompositeFunction. For example,

 composite=ProductFunction;name=LinearBackground;name=ExpDecay

To define a composite function inside a composite function enclose the inner one in brackets:

 name=LinearBackground;(composite=Convolution;name=Resolution;name=Lorentzian)

 *WIKI*/
32
33
34
35
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/Exception.h"
36
37
#include "MantidAPI/CompositeFunction.h"
#include "MantidAPI/ParameterTie.h"
38
#include "MantidAPI/IConstraint.h"
39
#include "MantidAPI/FunctionFactory.h"
40

41
#include <boost/lexical_cast.hpp>
42
43
44
#include <boost/shared_array.hpp>
#include <sstream>
#include <iostream>
45
#include <algorithm>
46
47
48
49
50
51

namespace Mantid
{
namespace API
{

Peterson, Peter's avatar
Peterson, Peter committed
52
53
using std::size_t;

54
DECLARE_FUNCTION(CompositeFunction)
55

56
57
/// Default constructor
CompositeFunction::CompositeFunction(): 
58
m_nParams(0)
59
60
61
62
{
  declareAttribute("NumDeriv", Attribute(false));
}

63
64
65
66
67
68
69
70
71
72
///Destructor
CompositeFunction::~CompositeFunction()
{
}

/// Function initialization. Declare function parameters in this method.
void CompositeFunction::init()
{
}

73
74
75
76
77
78
79
80
81
82
83
/** 
 * Writes itself into a string. Functions derived from CompositeFunction must
 * override this method with something like this:
 *   std::string NewFunction::asString()const
 *   {
 *      ostr << "composite=" << this->name() << ';';
 *      // write NewFunction's own attributes and parameters
 *      ostr << CompositeFunction::asString();
 *      // write NewFunction's own ties and constraints
 *      // ostr << ";constraints=(" << ... <<")";
 *   }
84
 * @return the string representation of the composite function
85
 */
86
87
88
std::string CompositeFunction::asString()const
{
  std::ostringstream ostr;
89
90
91
92
93
94
95
  
  // if empty just return function name
  if (nFunctions() == 0)
  {
    return "name=" + name();
  }

96
  if ( name() != "CompositeFunction" || nAttributes() > 1 || getAttribute("NumDeriv").asBool() == true )
97
  {
98
99
100
101
102
103
104
105
106
107
108
109
    ostr << "composite=" <<name() ;
    std::vector<std::string> attr = this->getAttributeNames();
    for(size_t i=0;i<attr.size();i++)
    {
      std::string attName = attr[i];
      std::string attValue = this->getAttribute(attr[i]).value();
      if (!attValue.empty())
      {
        ostr<<','<<attName<<'='<<attValue;
      }
    }
    ostr << ';';
110
  }
Peterson, Peter's avatar
Peterson, Peter committed
111
  for(size_t i=0;i<nFunctions();i++)
112
  {
113
114
    IFunction_sptr fun = getFunction(i);
    bool isComp = boost::dynamic_pointer_cast<CompositeFunction>(fun) != 0;
115
    if (isComp) ostr << '(';
116
    ostr << fun->asString();
117
    if (isComp) ostr << ')';
118
119
120
121
122
123
    if (i < nFunctions() - 1)
    {
      ostr << ';';
    }
  }
  std::string ties;
124
  for(size_t i=0;i<nParams();i++)
125
126
127
128
  {
    const ParameterTie* tie = getTie(i);
    if (tie)
    {
129
130
      IFunction_sptr fun = getFunction(functionIndex(i));
      std::string tmp = tie->asString(fun.get());
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
      if (tmp.empty())
      {
        tmp = tie->asString(this);
        if (!tmp.empty())
        {
          if (!ties.empty())
          {
            ties += ",";
          }
          ties += tmp;
        }
      }
    }
  }
  if (!ties.empty())
  {
    ostr << ";ties=(" << ties << ")";
148
149
150
151
  }
  return ostr.str();
}

152
153
154
155
156
157
158
159
160
161
162
163
164
/**
 * @param ws A pointer to the workspace being fitted
 */
void CompositeFunction::setWorkspace(boost::shared_ptr<const Workspace> ws)
{
  // Pass it on to each member
  auto iend = m_functions.end();
  for(auto it = m_functions.begin(); it != iend; ++it)
  {
    (*it)->setWorkspace(ws);
  }
}

165
/** Function you want to fit to. 
166
167
 *  @param domain :: An instance of FunctionDomain with the function arguments.
 *  @param values :: A FunctionValues instance for storing the calculated values.
168
169
170
171
 */
void CompositeFunction::function(const FunctionDomain& domain, FunctionValues& values)const
{
  FunctionValues tmp(domain);
172
  values.zeroCalculated();
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
  {
    m_functions[ iFun ]->function(domain,tmp);
    values += tmp;
  }
}

/**
 * Derivatives of function with respect to active parameters
 * @param domain :: Function domain to get the arguments from.
 * @param jacobian :: A Jacobian to store the derivatives.
 */
void CompositeFunction::functionDeriv(const FunctionDomain& domain, Jacobian& jacobian)
{
187
  if ( getAttribute("NumDeriv").asBool() )
188
189
190
191
  {
    calNumericalDeriv(domain, jacobian);
  }
  else
192
  {
193
194
195
196
197
    for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
    {
      PartialJacobian J(&jacobian,paramOffset(iFun));
      getFunction(iFun)->functionDeriv(domain,J);
    }
198
199
200
  }
}

201
/** Sets a new value to the i-th parameter.
202
203
204
 *  @param i :: The parameter index
 *  @param value :: The new value
 *  @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
205
 */
206
void CompositeFunction::setParameter(size_t i, const double& value, bool explicitlySet)
207
{
208
  size_t iFun = functionIndex(i);
209
  m_functions[ iFun ]->setParameter(i - m_paramOffsets[iFun],value,explicitlySet);
210
211
}

212
213
214
215
216
217
/** Sets a new description to the i-th parameter.
 *  @param i :: The parameter index
 *  @param description :: The new description
 */
void CompositeFunction::setParameterDescription(size_t i, const std::string& description)
{
218
  size_t iFun = functionIndex(i);
219
220
221
  m_functions[ iFun ]->setParameterDescription(i - m_paramOffsets[iFun],description);
}

222
/** Get the i-th parameter.
223
 *  @param i :: The parameter index
224
 *  @return value of the requested parameter
225
 */
226
double CompositeFunction::getParameter(size_t i)const
227
{
Peterson, Peter's avatar
Peterson, Peter committed
228
  size_t iFun = functionIndex(i);
229
  return m_functions[ iFun ]->getParameter(i - m_paramOffsets[iFun]);
230
231
}

232
233
/**
 * Sets a new value to a parameter by name.
234
235
236
 * @param name :: The name of the parameter.
 * @param value :: The new value
 * @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
237
238
 */
void CompositeFunction::setParameter(const std::string& name, const double& value, bool explicitlySet)
239
{
240
  std::string pname;
241
  size_t index;
242
  parseName(name,index,pname);
243
  getFunction(index)->setParameter(pname,value,explicitlySet);
244
245
}

246
247
248
/**
 * Sets a new description to a parameter by name.
 * @param name :: The name of the parameter.
249
 * @param description :: The new description
250
251
252
253
 */
void CompositeFunction::setParameterDescription(const std::string& name, const std::string& description)
{
  std::string pname;
254
  size_t index;
255
  parseName(name,index,pname);
256
  getFunction(index)->setParameterDescription(pname,description);
257
258
}

259
260
/**
 * Parameters by name.
261
 * @param name :: The name of the parameter.
262
 * @return value of the requested named parameter
263
 */
264
265
double CompositeFunction::getParameter(const std::string& name)const
{
266
  std::string pname;
267
  size_t index;
268
  parseName(name,index,pname);
269
  return getFunction(index)->getParameter(pname);
270
271
272
}

/// Total number of parameters
273
size_t CompositeFunction::nParams()const
274
275
276
277
{
  return m_nParams;
}

278
/**
279
 * 
280
 * @param name :: The name of a parameter
281
 * @return index of the requested named parameter
282
 */
283
size_t CompositeFunction::parameterIndex(const std::string& name)const
284
{
285
  std::string pname;
286
  size_t index;
287
  parseName(name,index,pname);
288
  return getFunction(index)->parameterIndex(pname) + m_paramOffsets[index];
289
290
}

Nick Draper's avatar
re #100    
Nick Draper committed
291
/// Returns the name of parameter
292
/// @param i :: The index
Nick Draper's avatar
re #100    
Nick Draper committed
293
/// @return The name of the parameter
294
std::string CompositeFunction::parameterName(size_t i)const
295
{
296
  size_t iFun = functionIndex(i);
297
298
299
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
  return ostr.str();
300
301
}

302
303
304
305
306
/// Returns the description of parameter
/// @param i :: The index
/// @return The description of the parameter
std::string CompositeFunction::parameterDescription(size_t i)const
{
307
  size_t iFun = functionIndex(i);
308
309
310
311
312
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->parameterDescription(i - m_paramOffsets[iFun]);
  return ostr.str();
}

313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/** 
 * Get the fitting error for a parameter
 * @param i :: The index of a parameter
 * @return :: the error
 */
double CompositeFunction::getError(size_t i) const
{
  size_t iFun = functionIndex(i);
  return m_functions[ iFun ]->getError(i - m_paramOffsets[iFun]);
}

/** 
 * Set the fitting error for a parameter
 * @param i :: The index of a parameter
 * @param err :: The error value to set
 */
void CompositeFunction::setError(size_t i, double err)
{
  size_t iFun = functionIndex(i);
  m_functions[ iFun ]->setError(i - m_paramOffsets[iFun], err);
}

335
/// Value of i-th active parameter. Override this method to make fitted parameters different from the declared
336
double CompositeFunction::activeParameter(size_t i)const
337
{
338
339
  size_t iFun = functionIndex(i);
  return m_functions[ iFun ]->activeParameter(i - m_paramOffsets[iFun]);
340
341
342
}

/// Set new value of i-th active parameter. Override this method to make fitted parameters different from the declared
343
void CompositeFunction::setActiveParameter(size_t i, double value)
344
{
345
346
  size_t iFun = functionIndex(i);
  m_functions[ iFun ]->setActiveParameter(i - m_paramOffsets[iFun],value);
347
348
349
}

/// Returns the name of active parameter i
350
std::string CompositeFunction::nameOfActive(size_t i)const
351
{
352
  size_t iFun = functionIndex(i);
353
  std::ostringstream ostr;
354
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->nameOfActive(i - m_paramOffsets[iFun]);
355
356
357
358
359
360
  return ostr.str();
}

/// Returns the description of active parameter i
std::string CompositeFunction::descriptionOfActive(size_t i)const
{
361
  size_t iFun = functionIndex(i);
362
  std::ostringstream ostr;
363
  ostr << m_functions[ iFun ]->descriptionOfActive(i - m_paramOffsets[iFun]);
364
  return ostr.str();
365
366
}

367
368
369
370
371
372
373
374
375
376
377
/**
 * query to see in the function is active
 * @param i :: The index of a declared parameter
 * @return true if parameter i is active
 */
bool CompositeFunction::isActive(size_t i)const
{
  size_t iFun = functionIndex(i);
  return m_functions[ iFun ]->isActive(i - m_paramOffsets[iFun]);
}

378
/**
379
 * query to see in the function is active
380
 * @param i :: The index of a declared parameter
381
 * @return true if parameter i is active
382
 */
383
bool CompositeFunction::isFixed(size_t i)const
384
{
385
  size_t iFun = functionIndex(i);
386
  return m_functions[ iFun ]->isFixed(i - m_paramOffsets[iFun]);
387
388
389
}

/**
390
 * @param i :: A declared parameter index to be removed from active
391
 */
392
void CompositeFunction::fix(size_t i)
393
{
394
  size_t iFun = functionIndex(i);
395
  m_functions[ iFun ]->fix(i - m_paramOffsets[iFun]);
396
397
}

398
/** Makes a parameter active again. It doesn't change the parameter's tie.
399
 * @param i :: A declared parameter index to be restored to active
400
 */
401
void CompositeFunction::unfix(size_t i)
402
{
403
  size_t iFun = functionIndex(i);
404
  m_functions[ iFun ]->unfix(i - m_paramOffsets[iFun]);
405
406
}

407
408
409
410
411
412
/** Makes sure that the function is consistent. 
 */
void CompositeFunction::checkFunction()
{
  m_nParams = 0;
  m_paramOffsets.clear();
413
  m_IFunction.clear();
414

415
  std::vector<IFunction_sptr> functions(m_functions.begin(),m_functions.end());
416
417
  m_functions.clear();

418
  for(std::vector<IFunction_sptr>::size_type i=0;i<functions.size();i++)
419
  {
420
421
    IFunction_sptr f = functions[i];
    CompositeFunction_sptr cf = boost::dynamic_pointer_cast<CompositeFunction>(f);
422
    if (cf) cf->checkFunction();
423
424
425
426
    addFunction(f);
  }
}

427
/** Add a function
428
 * @param f :: A pointer to the added function
429
 * @return The function index
430
 */
431
size_t CompositeFunction::addFunction(IFunction_sptr f)
432
{
433
  m_IFunction.insert(m_IFunction.end(),f->nParams(), m_functions.size());
434
435
436
437
438
439
440
441
442
443
444
445
  m_functions.push_back(f);
  //?f->init();
  if (m_paramOffsets.size() == 0)
  {
    m_paramOffsets.push_back(0);
    m_nParams = f->nParams();
  }
  else
  {
    m_paramOffsets.push_back(m_nParams);
    m_nParams += f->nParams();
  }
446
  return m_functions.size() - 1;
447
448
}

449
/** Remove a function
450
 * @param i :: The index of the function to remove
451
 */
452
void CompositeFunction::removeFunction(size_t i)
453
{
454
  if ( i >= nFunctions() )
455
456
    throw std::out_of_range("Function index out of range.");

457
  IFunction_sptr fun = getFunction(i);
458

459
  size_t dnp = fun->nParams();
460

461
  for(size_t j=0;j<nParams();)
462
463
  {
    ParameterTie* tie = getTie(j);
464
    if (tie && tie->findParametersOf(fun.get()))
465
466
467
468
469
470
471
472
473
474
    {
      removeTie(j);
    }
    else
    {
      j++;
    }
  }

  // Shift down the function indeces for parameters
475
  for(std::vector<size_t>::iterator it=m_IFunction.begin();it!=m_IFunction.end();)
476
  {
477

478
479
    if (*it == i)
    {
480
      it = m_IFunction.erase(it);
481
    }
482
    else
483
    {
484
485
486
487
      if (*it > i)
      {
        *it -= 1;
      }
488
      ++it;
489
490
491
492
493
    }
  }

  m_nParams -= dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
494
  for(size_t j=i+1;j<nFunctions();j++)
495
496
497
498
499
500
501
502
  {
    m_paramOffsets[j] -= dnp;
  }
  m_paramOffsets.erase(m_paramOffsets.begin()+i);

  m_functions.erase(m_functions.begin()+i);
}

503
/** Replace a function with a new one. The old function is deleted.
504
 *  The new function must have already its workspace set.
505
 * @param f_old :: The pointer to the function to replace. If it's not
506
 *  a member of this composite function nothing happens
507
 * @param f_new :: A pointer to the new function
508
 */
509
void CompositeFunction::replaceFunctionPtr(const IFunction_sptr f_old,IFunction_sptr f_new)
510
{
511
  std::vector<IFunction_sptr>::const_iterator it = 
512
513
    std::find(m_functions.begin(),m_functions.end(),f_old);
  if (it == m_functions.end()) return;
514
  std::vector<IFunction_sptr>::difference_type iFun = it - m_functions.begin();
515
  replaceFunction(iFun,f_new);
516
517
}

518
/** Replace a function with a new one. The old function is deleted.
519
520
 * @param i :: The index of the function to replace
 * @param f :: A pointer to the new function
521
 */
522
void CompositeFunction::replaceFunction(size_t i,IFunction_sptr f)
523
{
524
  if ( i >= nFunctions() )
525
526
    throw std::out_of_range("Function index out of range.");

527
  IFunction_sptr fun = getFunction(i);
528
  size_t np_old = fun->nParams();
529

530
  size_t np_new = f->nParams();
531
532
533

  // Modify function indeces: The new function may have different number of parameters
  {
534
535
    std::vector<size_t>::iterator itFun = std::find(m_IFunction.begin(),m_IFunction.end(),i);
    if(itFun != m_IFunction.end()) // functions must have at least 1 parameter
536
    {
537
538
      if (np_old > np_new)
      {
539
        m_IFunction.erase(itFun,itFun + np_old - np_new);
540
541
542
      }
      else if (np_old < np_new) 
      {
543
        m_IFunction.insert(itFun,np_new - np_old,i);
544
      }
545
    }
546
547
    else if (np_new > 0) // it could happen if the old function is an empty CompositeFunction
    {
548
549
      itFun = std::find_if(m_IFunction.begin(),m_IFunction.end(),std::bind2nd(std::greater<size_t>(),i));
      m_IFunction.insert(itFun,np_new,i);
550
    }
551
552
  }

553
  size_t dnp = np_new - np_old;
554
555
  m_nParams += dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
556
  for(size_t j=i+1;j<nFunctions();j++)
557
558
559
560
561
562
563
  {
    m_paramOffsets[j] += dnp;
  }

  m_functions[i] = f;
}

564
/**
565
 * @param i :: The index of the function
566
 * @return function at the requested index
567
 */
568
IFunction_sptr CompositeFunction::getFunction(std::size_t i)const
569
{
Peterson, Peter's avatar
Peterson, Peter committed
570
  if ( i >= nFunctions() )
571
  {
572
    throw std::out_of_range("Function index out of range.");
573
  }
574
575
576
  return m_functions[i];
}

577
578
/**
 * Get the index of the function to which parameter i belongs
579
 * @param i :: The parameter index
580
 * @return function index of the requested parameter
581
 */
582
size_t CompositeFunction::functionIndex(std::size_t i)const
583
{
584
  if( i >= nParams() )
585
  {
586
    throw std::out_of_range("Function parameter index out of range.");
587
  }
588
  return m_IFunction[i];
589
590
591
}

/**
592
* @param varName :: The variable name which may contain function index ( [f<index.>]name )
593
* @param index :: Receives function index or throws std::invalid_argument
594
* @param name :: Receives the parameter name
595
*/
596
void CompositeFunction::parseName(const std::string& varName,size_t& index, std::string& name)
597
{
598
599
600
  size_t i = varName.find('.');
  if (i == std::string::npos)
  {
601
    throw std::invalid_argument("Parameter " + varName + " not found.");
602
603
604
605
606
607
  }
  else
  {
    if (varName[0] != 'f')
      throw std::invalid_argument("External function parameter name must start with 'f'");

608
    std::string sindex = varName.substr(1,i - 1);
609
610
611
612
613
614
615
    index = boost::lexical_cast<int>(sindex);

    if (i == varName.size() - 1)
      throw std::invalid_argument("Name cannot be empty");

    name = varName.substr(i+1);
  }
616
617
}

618
/** Returns the index of parameter i as it declared in its function
619
 * @param i :: The parameter index
620
621
 * @return The local index of the parameter
 */
622
size_t CompositeFunction::parameterLocalIndex(size_t i)const
623
{
624
  size_t iFun = functionIndex(i);
625
626
627
  return i - m_paramOffsets[iFun];
}

628
/** Returns the name of parameter i as it declared in its function
629
 * @param i :: The parameter index
630
631
 * @return The pure parameter name (without the function identifier f#.)
 */
632
std::string CompositeFunction::parameterLocalName(size_t i)const
633
{
634
  size_t iFun = functionIndex(i);
635
636
637
  return m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
}

638
/**
639
 * Apply the ties.
640
641
642
 */
void CompositeFunction::applyTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
643
  for(size_t i=0;i<nFunctions();i++)
644
645
646
647
648
649
650
651
652
653
  {
    getFunction(i)->applyTies();
  }
}

/**
 * Clear the ties. 
 */
void CompositeFunction::clearTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
654
  for(size_t i=0;i<nFunctions();i++)
655
656
657
658
659
660
  {
    getFunction(i)->clearTies();
  }
}

/** Removes i-th parameter's tie if it is tied or does nothing.
661
 * @param i :: The index of the tied parameter.
662
663
 * @return True if successfull
 */
664
bool CompositeFunction::removeTie(size_t i)
665
{
666
  size_t iFun = functionIndex(i);
667
668
669
670
671
  bool res = m_functions[ iFun ]->removeTie(i - m_paramOffsets[iFun]);
  return res;
}

/** Get the tie of i-th parameter
672
 * @param i :: The parameter index
673
 * @return A pointer to the tie.
674
 */
675
ParameterTie* CompositeFunction::getTie(size_t i)const
676
{
677
  size_t iFun = functionIndex(i);
678
679
680
681
682
  return m_functions[ iFun ]->getTie(i - m_paramOffsets[iFun]);
}

/**
 * Attaches a tie to this function. The attached tie is owned by the function.
683
 * @param tie :: A pointer to a new tie
684
685
686
 */
void CompositeFunction::addTie(ParameterTie* tie)
{
687
688
  size_t i = getParameterIndex(*tie);
  size_t iFun = functionIndex(i);
689
690
691
692
693
  m_functions[iFun]->addTie(tie);
}

/**
 * Declare a new parameter. To used in the implementation'c constructor.
694
695
 * @param name :: The parameter name.
 * @param initValue :: The initial value for the parameter
696
 * @param description :: Parameter documentation
697
 */
698
void CompositeFunction::declareParameter(const std::string& name, double initValue, const std::string& description)
699
{
700
701
  (void) name; //Avoid compiler warning
  (void) initValue; //Avoid compiler warning
702
  (void) description; //Avoid compiler warning
703
704
705
706
  throw Kernel::Exception::NotImplementedError("CompositeFunction cannot not have its own parameters.");
}

/** Add a constraint
707
 *  @param ic :: Pointer to a constraint.
708
709
710
 */
void CompositeFunction::addConstraint(IConstraint* ic)
{
711
712
  size_t i = getParameterIndex(*ic);
  size_t iFun = functionIndex(i);
713
  getFunction(iFun)->addConstraint(ic);
714
715
}

716
717
718
/**
 * Prepare the function for a fit.
 */
719
void CompositeFunction::setUpForFit()
720
{
721
  // set up the member functions
Peterson, Peter's avatar
Peterson, Peter committed
722
  for(size_t i=0;i<nFunctions();i++)
723
  {
724
    getFunction(i)->setUpForFit();
725
  }
726
727
728
729
  // unfortuately the code below breaks some system tests (IRISFuryAndFuryFit)
  // it looks as if using numeric derivatives can give different fit results
  // to fit with analytical ones
  //
730
  // if parameters have non-constant ties enable numerical derivatives
731
732
733
734
735
736
737
738
739
740
741
742
  //for(size_t i = 0; i < nParams(); ++i)
  //{
  //  ParameterTie* tie = getTie( i );
  //  if ( tie && !tie->isConstant() )
  //  {
  //    useNumericDerivatives( true );
  //    break;
  //  }
  //}

  // instead of automatically switching to numeric derivatives
  // log a warning about a danger of not using it
743
  if ( !getAttribute("NumDeriv").asBool() )
744
  {
745
    for(size_t i = 0; i < nParams(); ++i)
746
    {
747
748
749
750
751
752
      ParameterTie* tie = getTie( i );
      if ( tie && !tie->isConstant() )
      {
        g_log.warning() << "Numeric derivatives should be used when non-constant ties defined." << std::endl;
        break;
      }
753
    }
754
755
756
  }
}

Nick Draper's avatar
re #100    
Nick Draper committed
757
/// Get constraint
758
/// @param i :: the index
Nick Draper's avatar
re #100    
Nick Draper committed
759
/// @return A pointer to the constraint
760
IConstraint* CompositeFunction::getConstraint(size_t i)const
761
{
762
  size_t iFun = functionIndex(i);
763
  return m_functions[ iFun ]->getConstraint(i - m_paramOffsets[iFun]);
764
765
}

766
/** Remove a constraint
767
 * @param parName :: The name of a parameter which constarint to remove.
768
769
770
 */
void CompositeFunction::removeConstraint(const std::string& parName)
{
771
772
  size_t iPar = parameterIndex(parName);
  size_t iFun = functionIndex(iPar);
773
774
775
  getFunction(iFun)->removeConstraint(parameterLocalName(iPar));
}

776
/** Checks if a constraint has been explicitly set
777
 *  @param i :: The parameter index
778
 *  @return true if the function is explicitly set
779
 */
780
bool CompositeFunction::isExplicitlySet(size_t i)const
781
{
782
  size_t iFun = functionIndex(i);
783
784
785
  return m_functions[ iFun ]->isExplicitlySet(i - m_paramOffsets[iFun]);
}

786
/**
787
 * Returns the index of parameter if the ref points to one of the member function
788
 * @param ref :: A reference to a parameter
789
 * @return Parameter index or number of nParams() if parameter not found
790
 */
791
size_t CompositeFunction::getParameterIndex(const ParameterReference& ref)const
792
{
793
  if (ref.getFunction() == this && ref.getIndex() < nParams())
794
  {
795
    return ref.getIndex();
796
  }
Peterson, Peter's avatar
Peterson, Peter committed
797
  for(size_t iFun=0;iFun<nFunctions();iFun++)
798
  {
799
    IFunction_sptr fun = getFunction(iFun);
800
801
    size_t iLocalIndex = fun->getParameterIndex(ref);
    if (iLocalIndex < fun->nParams())
802
803
804
805
    {
      return m_paramOffsets[iFun] + iLocalIndex;
    }
  }
806
  return nParams();
807
808
}

809
/**
810
 * Returns the shrared pointer to the function conataining a parameter
811
 * @param ref :: The reference
812
813
 * @return A function containing parameter pointed to by ref
 */
814
IFunction_sptr CompositeFunction::getContainingFunction(const ParameterReference& ref)const
815
{
Peterson, Peter's avatar
Peterson, Peter committed
816
  for(size_t iFun=0;iFun<nFunctions();iFun++)
817
  {
818
819
    IFunction_sptr fun = getFunction(iFun);
    if (fun->getParameterIndex(ref) < fun->nParams())
820
    {
821
      return fun;
822
823
    }
  }
824
825
826
  return IFunction_sptr();
}

827
828
} // namespace API
} // namespace Mantid