CompositeFunction.cpp 24.4 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
/// Default constructor
57
58
CompositeFunction::CompositeFunction()
  : IFunction(), 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
166
167
168
169
170
171
172
173
174
175
176
177
178
/**
 * @param workspace :: A workspace to fit to.
 * @param wi :: An index of a spectrum to fit to.
 * @param startX :: A start of the fitting region.
 * @param endX :: An end of the fitting region.
 */
void CompositeFunction::setMatrixWorkspace(boost::shared_ptr<const MatrixWorkspace> workspace, size_t wi, double startX, double endX)
{
    for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
    {
        m_functions[ iFun ]->setMatrixWorkspace( workspace, wi, startX, endX );
    }
}

179
/** Function you want to fit to. 
180
181
 *  @param domain :: An instance of FunctionDomain with the function arguments.
 *  @param values :: A FunctionValues instance for storing the calculated values.
182
183
184
185
 */
void CompositeFunction::function(const FunctionDomain& domain, FunctionValues& values)const
{
  FunctionValues tmp(domain);
186
  values.zeroCalculated();
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  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)
{
201
  if ( getAttribute("NumDeriv").asBool() )
202
203
204
205
  {
    calNumericalDeriv(domain, jacobian);
  }
  else
206
  {
207
208
209
210
211
    for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
    {
      PartialJacobian J(&jacobian,paramOffset(iFun));
      getFunction(iFun)->functionDeriv(domain,J);
    }
212
213
214
  }
}

215
/** Sets a new value to the i-th parameter.
216
217
218
 *  @param i :: The parameter index
 *  @param value :: The new value
 *  @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
219
 */
220
void CompositeFunction::setParameter(size_t i, const double& value, bool explicitlySet)
221
{
222
  size_t iFun = functionIndex(i);
223
  m_functions[ iFun ]->setParameter(i - m_paramOffsets[iFun],value,explicitlySet);
224
225
}

226
227
228
229
230
231
/** 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)
{
232
  size_t iFun = functionIndex(i);
233
234
235
  m_functions[ iFun ]->setParameterDescription(i - m_paramOffsets[iFun],description);
}

236
/** Get the i-th parameter.
237
 *  @param i :: The parameter index
238
 *  @return value of the requested parameter
239
 */
240
double CompositeFunction::getParameter(size_t i)const
241
{
Peterson, Peter's avatar
Peterson, Peter committed
242
  size_t iFun = functionIndex(i);
243
  return m_functions[ iFun ]->getParameter(i - m_paramOffsets[iFun]);
244
245
}

246
247
/**
 * Sets a new value to a parameter by name.
248
249
250
 * @param name :: The name of the parameter.
 * @param value :: The new value
 * @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
251
252
 */
void CompositeFunction::setParameter(const std::string& name, const double& value, bool explicitlySet)
253
{
254
  std::string pname;
255
  size_t index;
256
  parseName(name,index,pname);
257
  getFunction(index)->setParameter(pname,value,explicitlySet);
258
259
}

260
261
262
/**
 * Sets a new description to a parameter by name.
 * @param name :: The name of the parameter.
263
 * @param description :: The new description
264
265
266
267
 */
void CompositeFunction::setParameterDescription(const std::string& name, const std::string& description)
{
  std::string pname;
268
  size_t index;
269
  parseName(name,index,pname);
270
  getFunction(index)->setParameterDescription(pname,description);
271
272
}

273
274
/**
 * Parameters by name.
275
 * @param name :: The name of the parameter.
276
 * @return value of the requested named parameter
277
 */
278
279
double CompositeFunction::getParameter(const std::string& name)const
{
280
  std::string pname;
281
  size_t index;
282
  parseName(name,index,pname);
283
  return getFunction(index)->getParameter(pname);
284
285
286
}

/// Total number of parameters
287
size_t CompositeFunction::nParams()const
288
289
290
291
{
  return m_nParams;
}

292
/**
293
 * 
294
 * @param name :: The name of a parameter
295
 * @return index of the requested named parameter
296
 */
297
size_t CompositeFunction::parameterIndex(const std::string& name)const
298
{
299
  std::string pname;
300
  size_t index;
301
  parseName(name,index,pname);
302
  return getFunction(index)->parameterIndex(pname) + m_paramOffsets[index];
303
304
}

Nick Draper's avatar
re #100    
Nick Draper committed
305
/// Returns the name of parameter
306
/// @param i :: The index
Nick Draper's avatar
re #100    
Nick Draper committed
307
/// @return The name of the parameter
308
std::string CompositeFunction::parameterName(size_t i)const
309
{
310
  size_t iFun = functionIndex(i);
311
312
313
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
  return ostr.str();
314
315
}

316
317
318
319
320
/// Returns the description of parameter
/// @param i :: The index
/// @return The description of the parameter
std::string CompositeFunction::parameterDescription(size_t i)const
{
321
  size_t iFun = functionIndex(i);
322
323
324
325
326
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->parameterDescription(i - m_paramOffsets[iFun]);
  return ostr.str();
}

327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
/** 
 * 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);
}

349
/// Value of i-th active parameter. Override this method to make fitted parameters different from the declared
350
double CompositeFunction::activeParameter(size_t i)const
351
{
352
353
  size_t iFun = functionIndex(i);
  return m_functions[ iFun ]->activeParameter(i - m_paramOffsets[iFun]);
354
355
356
}

/// Set new value of i-th active parameter. Override this method to make fitted parameters different from the declared
357
void CompositeFunction::setActiveParameter(size_t i, double value)
358
{
359
360
  size_t iFun = functionIndex(i);
  m_functions[ iFun ]->setActiveParameter(i - m_paramOffsets[iFun],value);
361
362
363
}

/// Returns the name of active parameter i
364
std::string CompositeFunction::nameOfActive(size_t i)const
365
{
366
  size_t iFun = functionIndex(i);
367
  std::ostringstream ostr;
368
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->nameOfActive(i - m_paramOffsets[iFun]);
369
370
371
372
373
374
  return ostr.str();
}

/// Returns the description of active parameter i
std::string CompositeFunction::descriptionOfActive(size_t i)const
{
375
  size_t iFun = functionIndex(i);
376
  std::ostringstream ostr;
377
  ostr << m_functions[ iFun ]->descriptionOfActive(i - m_paramOffsets[iFun]);
378
  return ostr.str();
379
380
}

381
382
383
384
385
386
387
388
389
390
391
/**
 * 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]);
}

392
/**
393
 * query to see in the function is active
394
 * @param i :: The index of a declared parameter
395
 * @return true if parameter i is active
396
 */
397
bool CompositeFunction::isFixed(size_t i)const
398
{
399
  size_t iFun = functionIndex(i);
400
  return m_functions[ iFun ]->isFixed(i - m_paramOffsets[iFun]);
401
402
403
}

/**
404
 * @param i :: A declared parameter index to be removed from active
405
 */
406
void CompositeFunction::fix(size_t i)
407
{
408
  size_t iFun = functionIndex(i);
409
  m_functions[ iFun ]->fix(i - m_paramOffsets[iFun]);
410
411
}

412
/** Makes a parameter active again. It doesn't change the parameter's tie.
413
 * @param i :: A declared parameter index to be restored to active
414
 */
415
void CompositeFunction::unfix(size_t i)
416
{
417
  size_t iFun = functionIndex(i);
418
  m_functions[ iFun ]->unfix(i - m_paramOffsets[iFun]);
419
420
}

421
422
423
424
425
426
/** Makes sure that the function is consistent. 
 */
void CompositeFunction::checkFunction()
{
  m_nParams = 0;
  m_paramOffsets.clear();
427
  m_IFunction.clear();
428

429
  std::vector<IFunction_sptr> functions(m_functions.begin(),m_functions.end());
430
431
  m_functions.clear();

432
  for(std::vector<IFunction_sptr>::size_type i=0;i<functions.size();i++)
433
  {
434
435
    IFunction_sptr f = functions[i];
    CompositeFunction_sptr cf = boost::dynamic_pointer_cast<CompositeFunction>(f);
436
    if (cf) cf->checkFunction();
437
438
439
440
    addFunction(f);
  }
}

441
/** Add a function
442
 * @param f :: A pointer to the added function
443
 * @return The function index
444
 */
445
size_t CompositeFunction::addFunction(IFunction_sptr f)
446
{
447
  m_IFunction.insert(m_IFunction.end(),f->nParams(), m_functions.size());
448
449
450
451
452
453
454
455
456
457
458
459
  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();
  }
460
  return m_functions.size() - 1;
461
462
}

463
/** Remove a function
464
 * @param i :: The index of the function to remove
465
 */
466
void CompositeFunction::removeFunction(size_t i)
467
{
468
  if ( i >= nFunctions() )
469
470
    throw std::out_of_range("Function index out of range.");

471
  IFunction_sptr fun = getFunction(i);
472

473
  size_t dnp = fun->nParams();
474

475
  for(size_t j=0;j<nParams();)
476
477
  {
    ParameterTie* tie = getTie(j);
478
    if (tie && tie->findParametersOf(fun.get()))
479
480
481
482
483
484
485
486
487
488
    {
      removeTie(j);
    }
    else
    {
      j++;
    }
  }

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

492
493
    if (*it == i)
    {
494
      it = m_IFunction.erase(it);
495
    }
496
    else
497
    {
498
499
500
501
      if (*it > i)
      {
        *it -= 1;
      }
502
      ++it;
503
504
505
506
507
    }
  }

  m_nParams -= dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
508
  for(size_t j=i+1;j<nFunctions();j++)
509
510
511
512
513
514
515
516
  {
    m_paramOffsets[j] -= dnp;
  }
  m_paramOffsets.erase(m_paramOffsets.begin()+i);

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

517
/** Replace a function with a new one. The old function is deleted.
518
 *  The new function must have already its workspace set.
519
 * @param f_old :: The pointer to the function to replace. If it's not
520
 *  a member of this composite function nothing happens
521
 * @param f_new :: A pointer to the new function
522
 */
523
void CompositeFunction::replaceFunctionPtr(const IFunction_sptr f_old,IFunction_sptr f_new)
524
{
525
  std::vector<IFunction_sptr>::const_iterator it = 
526
527
    std::find(m_functions.begin(),m_functions.end(),f_old);
  if (it == m_functions.end()) return;
528
  std::vector<IFunction_sptr>::difference_type iFun = it - m_functions.begin();
529
  replaceFunction(iFun,f_new);
530
531
}

532
/** Replace a function with a new one. The old function is deleted.
533
534
 * @param i :: The index of the function to replace
 * @param f :: A pointer to the new function
535
 */
536
void CompositeFunction::replaceFunction(size_t i,IFunction_sptr f)
537
{
538
  if ( i >= nFunctions() )
539
540
    throw std::out_of_range("Function index out of range.");

541
  IFunction_sptr fun = getFunction(i);
542
  size_t np_old = fun->nParams();
543

544
  size_t np_new = f->nParams();
545
546
547

  // Modify function indeces: The new function may have different number of parameters
  {
548
549
    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
550
    {
551
552
      if (np_old > np_new)
      {
553
        m_IFunction.erase(itFun,itFun + np_old - np_new);
554
555
556
      }
      else if (np_old < np_new) 
      {
557
        m_IFunction.insert(itFun,np_new - np_old,i);
558
      }
559
    }
560
561
    else if (np_new > 0) // it could happen if the old function is an empty CompositeFunction
    {
562
563
      itFun = std::find_if(m_IFunction.begin(),m_IFunction.end(),std::bind2nd(std::greater<size_t>(),i));
      m_IFunction.insert(itFun,np_new,i);
564
    }
565
566
  }

567
  size_t dnp = np_new - np_old;
568
569
  m_nParams += dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
570
  for(size_t j=i+1;j<nFunctions();j++)
571
572
573
574
575
576
577
  {
    m_paramOffsets[j] += dnp;
  }

  m_functions[i] = f;
}

578
/**
579
 * @param i :: The index of the function
580
 * @return function at the requested index
581
 */
582
IFunction_sptr CompositeFunction::getFunction(std::size_t i)const
583
{
Peterson, Peter's avatar
Peterson, Peter committed
584
  if ( i >= nFunctions() )
585
  {
586
    throw std::out_of_range("Function index out of range.");
587
  }
588
589
590
  return m_functions[i];
}

591
592
/**
 * Get the index of the function to which parameter i belongs
593
 * @param i :: The parameter index
594
 * @return function index of the requested parameter
595
 */
596
size_t CompositeFunction::functionIndex(std::size_t i)const
597
{
598
  if( i >= nParams() )
599
  {
600
    throw std::out_of_range("Function parameter index out of range.");
601
  }
602
  return m_IFunction[i];
603
604
605
}

/**
606
* @param varName :: The variable name which may contain function index ( [f<index.>]name )
607
* @param index :: Receives function index or throws std::invalid_argument
608
* @param name :: Receives the parameter name
609
*/
610
void CompositeFunction::parseName(const std::string& varName,size_t& index, std::string& name)
611
{
612
613
614
  size_t i = varName.find('.');
  if (i == std::string::npos)
  {
615
    throw std::invalid_argument("Parameter " + varName + " not found.");
616
617
618
619
620
621
  }
  else
  {
    if (varName[0] != 'f')
      throw std::invalid_argument("External function parameter name must start with 'f'");

622
    std::string sindex = varName.substr(1,i - 1);
623
624
625
626
627
628
629
    index = boost::lexical_cast<int>(sindex);

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

    name = varName.substr(i+1);
  }
630
631
}

632
/** Returns the index of parameter i as it declared in its function
633
 * @param i :: The parameter index
634
635
 * @return The local index of the parameter
 */
636
size_t CompositeFunction::parameterLocalIndex(size_t i)const
637
{
638
  size_t iFun = functionIndex(i);
639
640
641
  return i - m_paramOffsets[iFun];
}

642
/** Returns the name of parameter i as it declared in its function
643
 * @param i :: The parameter index
644
645
 * @return The pure parameter name (without the function identifier f#.)
 */
646
std::string CompositeFunction::parameterLocalName(size_t i)const
647
{
648
  size_t iFun = functionIndex(i);
649
650
651
  return m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
}

652
/**
653
 * Apply the ties.
654
655
656
 */
void CompositeFunction::applyTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
657
  for(size_t i=0;i<nFunctions();i++)
658
659
660
661
662
663
664
665
666
667
  {
    getFunction(i)->applyTies();
  }
}

/**
 * Clear the ties. 
 */
void CompositeFunction::clearTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
668
  for(size_t i=0;i<nFunctions();i++)
669
670
671
672
673
674
  {
    getFunction(i)->clearTies();
  }
}

/** Removes i-th parameter's tie if it is tied or does nothing.
675
 * @param i :: The index of the tied parameter.
676
677
 * @return True if successfull
 */
678
bool CompositeFunction::removeTie(size_t i)
679
{
680
  size_t iFun = functionIndex(i);
681
682
683
684
685
  bool res = m_functions[ iFun ]->removeTie(i - m_paramOffsets[iFun]);
  return res;
}

/** Get the tie of i-th parameter
686
 * @param i :: The parameter index
687
 * @return A pointer to the tie.
688
 */
689
ParameterTie* CompositeFunction::getTie(size_t i)const
690
{
691
  size_t iFun = functionIndex(i);
692
693
694
695
696
  return m_functions[ iFun ]->getTie(i - m_paramOffsets[iFun]);
}

/**
 * Attaches a tie to this function. The attached tie is owned by the function.
697
 * @param tie :: A pointer to a new tie
698
699
700
 */
void CompositeFunction::addTie(ParameterTie* tie)
{
701
702
  size_t i = getParameterIndex(*tie);
  size_t iFun = functionIndex(i);
703
704
705
706
707
  m_functions[iFun]->addTie(tie);
}

/**
 * Declare a new parameter. To used in the implementation'c constructor.
708
709
 * @param name :: The parameter name.
 * @param initValue :: The initial value for the parameter
710
 * @param description :: Parameter documentation
711
 */
712
void CompositeFunction::declareParameter(const std::string& name, double initValue, const std::string& description)
713
{
714
715
  (void) name; //Avoid compiler warning
  (void) initValue; //Avoid compiler warning
716
  (void) description; //Avoid compiler warning
717
718
719
720
  throw Kernel::Exception::NotImplementedError("CompositeFunction cannot not have its own parameters.");
}

/** Add a constraint
721
 *  @param ic :: Pointer to a constraint.
722
723
724
 */
void CompositeFunction::addConstraint(IConstraint* ic)
{
725
726
  size_t i = getParameterIndex(*ic);
  size_t iFun = functionIndex(i);
727
  getFunction(iFun)->addConstraint(ic);
728
729
}

730
731
732
/**
 * Prepare the function for a fit.
 */
733
void CompositeFunction::setUpForFit()
734
{
735
  // set up the member functions
Peterson, Peter's avatar
Peterson, Peter committed
736
  for(size_t i=0;i<nFunctions();i++)
737
  {
738
    getFunction(i)->setUpForFit();
739
  }
740
741
742
743
  // 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
  //
744
  // if parameters have non-constant ties enable numerical derivatives
745
746
747
748
749
750
751
752
753
754
755
756
  //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
757
  if ( !getAttribute("NumDeriv").asBool() )
758
  {
759
    for(size_t i = 0; i < nParams(); ++i)
760
    {
761
762
763
764
765
766
      ParameterTie* tie = getTie( i );
      if ( tie && !tie->isConstant() )
      {
        g_log.warning() << "Numeric derivatives should be used when non-constant ties defined." << std::endl;
        break;
      }
767
    }
768
769
770
  }
}

Nick Draper's avatar
re #100    
Nick Draper committed
771
/// Get constraint
772
/// @param i :: the index
Nick Draper's avatar
re #100    
Nick Draper committed
773
/// @return A pointer to the constraint
774
IConstraint* CompositeFunction::getConstraint(size_t i)const
775
{
776
  size_t iFun = functionIndex(i);
777
  return m_functions[ iFun ]->getConstraint(i - m_paramOffsets[iFun]);
778
779
}

780
/** Remove a constraint
781
 * @param parName :: The name of a parameter which constarint to remove.
782
783
784
 */
void CompositeFunction::removeConstraint(const std::string& parName)
{
785
786
  size_t iPar = parameterIndex(parName);
  size_t iFun = functionIndex(iPar);
787
788
789
  getFunction(iFun)->removeConstraint(parameterLocalName(iPar));
}

790
/** Checks if a constraint has been explicitly set
791
 *  @param i :: The parameter index
792
 *  @return true if the function is explicitly set
793
 */
794
bool CompositeFunction::isExplicitlySet(size_t i)const
795
{
796
  size_t iFun = functionIndex(i);
797
798
799
  return m_functions[ iFun ]->isExplicitlySet(i - m_paramOffsets[iFun]);
}

800
/**
801
 * Returns the index of parameter if the ref points to one of the member function
802
 * @param ref :: A reference to a parameter
803
 * @return Parameter index or number of nParams() if parameter not found
804
 */
805
size_t CompositeFunction::getParameterIndex(const ParameterReference& ref)const
806
{
807
  if (ref.getFunction() == this && ref.getIndex() < nParams())
808
  {
809
    return ref.getIndex();
810
  }
Peterson, Peter's avatar
Peterson, Peter committed
811
  for(size_t iFun=0;iFun<nFunctions();iFun++)
812
  {
813
    IFunction_sptr fun = getFunction(iFun);
814
815
    size_t iLocalIndex = fun->getParameterIndex(ref);
    if (iLocalIndex < fun->nParams())
816
817
818
819
    {
      return m_paramOffsets[iFun] + iLocalIndex;
    }
  }
820
  return nParams();
821
822
}

823
/**
824
 * Returns the shrared pointer to the function conataining a parameter
825
 * @param ref :: The reference
826
827
 * @return A function containing parameter pointed to by ref
 */
828
IFunction_sptr CompositeFunction::getContainingFunction(const ParameterReference& ref)const
829
{
Peterson, Peter's avatar
Peterson, Peter committed
830
  for(size_t iFun=0;iFun<nFunctions();iFun++)
831
  {
832
833
    IFunction_sptr fun = getFunction(iFun);
    if (fun->getParameterIndex(ref) < fun->nParams())
834
    {
835
      return fun;
836
837
    }
  }
838
839
840
  return IFunction_sptr();
}

841
842
} // namespace API
} // namespace Mantid