CompositeFunction.cpp 21.7 KB
Newer Older
1
2
3
4
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/Exception.h"
5
6
#include "MantidAPI/CompositeFunction.h"
#include "MantidAPI/ParameterTie.h"
7
#include "MantidAPI/IConstraint.h"
8
#include "MantidAPI/FunctionFactory.h"
9

10
#include <boost/lexical_cast.hpp>
11
12
13
#include <boost/shared_array.hpp>
#include <sstream>
#include <iostream>
14
#include <algorithm>
15
16
17
18
19
20

namespace Mantid
{
namespace API
{

Peterson, Peter's avatar
Peterson, Peter committed
21
22
using std::size_t;

23
DECLARE_FUNCTION(CompositeFunction)
24

25
26
27
28
29
30
31
32
/// Default constructor
CompositeFunction::CompositeFunction(): 
m_nParams(0),
m_useNumericDerivatives(false)
{
  declareAttribute("NumDeriv", Attribute(false));
}

33
34
35
36
37
38
39
40
41
42
///Destructor
CompositeFunction::~CompositeFunction()
{
}

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

43
44
45
46
47
48
49
50
51
52
53
/** 
 * 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=(" << ... <<")";
 *   }
54
 * @return the string representation of the composite function
55
 */
56
57
58
std::string CompositeFunction::asString()const
{
  std::ostringstream ostr;
59
60
61
62
63
64
65
  
  // if empty just return function name
  if (nFunctions() == 0)
  {
    return "name=" + name();
  }

66
  if ( name() != "CompositeFunction" || nAttributes() > 1 || getAttribute("NumDeriv").asBool() == true )
67
  {
68
69
70
71
72
73
74
75
76
77
78
79
    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 << ';';
80
  }
Peterson, Peter's avatar
Peterson, Peter committed
81
  for(size_t i=0;i<nFunctions();i++)
82
  {
83
84
    IFunction_sptr fun = getFunction(i);
    bool isComp = boost::dynamic_pointer_cast<CompositeFunction>(fun) != 0;
85
    if (isComp) ostr << '(';
86
    ostr << fun->asString();
87
    if (isComp) ostr << ')';
88
89
90
91
92
93
    if (i < nFunctions() - 1)
    {
      ostr << ';';
    }
  }
  std::string ties;
94
  for(size_t i=0;i<nParams();i++)
95
96
97
98
  {
    const ParameterTie* tie = getTie(i);
    if (tie)
    {
99
100
      IFunction_sptr fun = getFunction(functionIndex(i));
      std::string tmp = tie->asString(fun.get());
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
      if (tmp.empty())
      {
        tmp = tie->asString(this);
        if (!tmp.empty())
        {
          if (!ties.empty())
          {
            ties += ",";
          }
          ties += tmp;
        }
      }
    }
  }
  if (!ties.empty())
  {
    ostr << ";ties=(" << ties << ")";
118
119
120
121
  }
  return ostr.str();
}

122
123
124
125
126
127
128
129
130
131
132
133
134
/**
 * @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);
  }
}

135
136
137
138
139
140
/** Function you want to fit to. 
 *  @param domain :: The buffer for writing the calculated values. Must be big enough to accept dataSize() values
 */
void CompositeFunction::function(const FunctionDomain& domain, FunctionValues& values)const
{
  FunctionValues tmp(domain);
141
  values.zeroCalculated();
142
143
144
145
146
147
148
149
150
151
152
153
154
155
  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)
{
156
157
158
159
160
  if ( m_useNumericDerivatives )
  {
    calNumericalDeriv(domain, jacobian);
  }
  else
161
  {
162
163
164
165
166
    for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
    {
      PartialJacobian J(&jacobian,paramOffset(iFun));
      getFunction(iFun)->functionDeriv(domain,J);
    }
167
168
169
  }
}

170
/** Sets a new value to the i-th parameter.
171
172
173
 *  @param i :: The parameter index
 *  @param value :: The new value
 *  @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
174
 */
175
void CompositeFunction::setParameter(size_t i, const double& value, bool explicitlySet)
176
{
177
  size_t iFun = functionIndex(i);
178
  m_functions[ iFun ]->setParameter(i - m_paramOffsets[iFun],value,explicitlySet);
179
180
}

181
182
183
184
185
186
/** 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)
{
187
  size_t iFun = functionIndex(i);
188
189
190
  m_functions[ iFun ]->setParameterDescription(i - m_paramOffsets[iFun],description);
}

191
/** Get the i-th parameter.
192
 *  @param i :: The parameter index
193
 *  @return value of the requested parameter
194
 */
195
double CompositeFunction::getParameter(size_t i)const
196
{
Peterson, Peter's avatar
Peterson, Peter committed
197
  size_t iFun = functionIndex(i);
198
  return m_functions[ iFun ]->getParameter(i - m_paramOffsets[iFun]);
199
200
}

201
202
/**
 * Sets a new value to a parameter by name.
203
204
205
 * @param name :: The name of the parameter.
 * @param value :: The new value
 * @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
206
207
 */
void CompositeFunction::setParameter(const std::string& name, const double& value, bool explicitlySet)
208
{
209
  std::string pname;
210
  size_t index;
211
  parseName(name,index,pname);
212
  getFunction(index)->setParameter(pname,value,explicitlySet);
213
214
}

215
216
217
/**
 * Sets a new description to a parameter by name.
 * @param name :: The name of the parameter.
218
 * @param description :: The new description
219
220
221
222
 */
void CompositeFunction::setParameterDescription(const std::string& name, const std::string& description)
{
  std::string pname;
223
  size_t index;
224
  parseName(name,index,pname);
225
  getFunction(index)->setParameterDescription(pname,description);
226
227
}

228
229
/**
 * Parameters by name.
230
 * @param name :: The name of the parameter.
231
 * @return value of the requested named parameter
232
 */
233
234
double CompositeFunction::getParameter(const std::string& name)const
{
235
  std::string pname;
236
  size_t index;
237
  parseName(name,index,pname);
238
  return getFunction(index)->getParameter(pname);
239
240
241
}

/// Total number of parameters
242
size_t CompositeFunction::nParams()const
243
244
245
246
{
  return m_nParams;
}

247
/**
248
 * 
249
 * @param name :: The name of a parameter
250
 * @return index of the requested named parameter
251
 */
252
size_t CompositeFunction::parameterIndex(const std::string& name)const
253
{
254
  std::string pname;
255
  size_t index;
256
  parseName(name,index,pname);
257
  return getFunction(index)->parameterIndex(pname) + m_paramOffsets[index];
258
259
}

Nick Draper's avatar
re #100    
Nick Draper committed
260
/// Returns the name of parameter
261
/// @param i :: The index
Nick Draper's avatar
re #100    
Nick Draper committed
262
/// @return The name of the parameter
263
std::string CompositeFunction::parameterName(size_t i)const
264
{
265
  size_t iFun = functionIndex(i);
266
267
268
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
  return ostr.str();
269
270
}

271
272
273
274
275
/// Returns the description of parameter
/// @param i :: The index
/// @return The description of the parameter
std::string CompositeFunction::parameterDescription(size_t i)const
{
276
  size_t iFun = functionIndex(i);
277
278
279
280
281
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->parameterDescription(i - m_paramOffsets[iFun]);
  return ostr.str();
}

282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
/** 
 * 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);
}

304
/// Value of i-th active parameter. Override this method to make fitted parameters different from the declared
305
double CompositeFunction::activeParameter(size_t i)const
306
{
307
308
  size_t iFun = functionIndex(i);
  return m_functions[ iFun ]->activeParameter(i - m_paramOffsets[iFun]);
309
310
311
}

/// Set new value of i-th active parameter. Override this method to make fitted parameters different from the declared
312
void CompositeFunction::setActiveParameter(size_t i, double value)
313
{
314
315
  size_t iFun = functionIndex(i);
  m_functions[ iFun ]->setActiveParameter(i - m_paramOffsets[iFun],value);
316
317
318
}

/// Returns the name of active parameter i
319
std::string CompositeFunction::nameOfActive(size_t i)const
320
{
321
  size_t iFun = functionIndex(i);
322
  std::ostringstream ostr;
323
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->nameOfActive(i - m_paramOffsets[iFun]);
324
325
326
327
328
329
  return ostr.str();
}

/// Returns the description of active parameter i
std::string CompositeFunction::descriptionOfActive(size_t i)const
{
330
  size_t iFun = functionIndex(i);
331
  std::ostringstream ostr;
332
  ostr << m_functions[ iFun ]->descriptionOfActive(i - m_paramOffsets[iFun]);
333
  return ostr.str();
334
335
}

336
337
338
339
340
341
342
343
344
345
346
/**
 * 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]);
}

347
/**
348
 * query to see in the function is active
349
 * @param i :: The index of a declared parameter
350
 * @return true if parameter i is active
351
 */
352
bool CompositeFunction::isFixed(size_t i)const
353
{
354
  size_t iFun = functionIndex(i);
355
  return m_functions[ iFun ]->isFixed(i - m_paramOffsets[iFun]);
356
357
358
}

/**
359
 * @param i :: A declared parameter index to be removed from active
360
 */
361
void CompositeFunction::fix(size_t i)
362
{
363
  size_t iFun = functionIndex(i);
364
  m_functions[ iFun ]->fix(i - m_paramOffsets[iFun]);
365
366
}

367
/** Makes a parameter active again. It doesn't change the parameter's tie.
368
 * @param i :: A declared parameter index to be restored to active
369
 */
370
void CompositeFunction::unfix(size_t i)
371
{
372
  size_t iFun = functionIndex(i);
373
  m_functions[ iFun ]->unfix(i - m_paramOffsets[iFun]);
374
375
}

376
377
378
379
380
381
/** Makes sure that the function is consistent. 
 */
void CompositeFunction::checkFunction()
{
  m_nParams = 0;
  m_paramOffsets.clear();
382
  m_IFunction.clear();
383

384
  std::vector<IFunction_sptr> functions(m_functions.begin(),m_functions.end());
385
386
  m_functions.clear();

387
  for(std::vector<IFunction_sptr>::size_type i=0;i<functions.size();i++)
388
  {
389
390
    IFunction_sptr f = functions[i];
    CompositeFunction_sptr cf = boost::dynamic_pointer_cast<CompositeFunction>(f);
391
    if (cf) cf->checkFunction();
392
393
394
395
    addFunction(f);
  }
}

396
/** Add a function
397
 * @param f :: A pointer to the added function
398
 * @return The function index
399
 */
400
size_t CompositeFunction::addFunction(IFunction_sptr f)
401
{
402
  m_IFunction.insert(m_IFunction.end(),f->nParams(), m_functions.size());
403
404
405
406
407
408
409
410
411
412
413
414
  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();
  }
415
  return m_functions.size() - 1;
416
417
}

418
/** Remove a function
419
 * @param i :: The index of the function to remove
420
 */
421
void CompositeFunction::removeFunction(size_t i)
422
{
423
  if ( i >= nFunctions() )
424
425
    throw std::out_of_range("Function index out of range.");

426
  IFunction_sptr fun = getFunction(i);
427

428
  size_t dnp = fun->nParams();
429

430
  for(size_t j=0;j<nParams();)
431
432
  {
    ParameterTie* tie = getTie(j);
433
    if (tie && tie->findParametersOf(fun.get()))
434
435
436
437
438
439
440
441
442
443
    {
      removeTie(j);
    }
    else
    {
      j++;
    }
  }

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

447
448
    if (*it == i)
    {
449
      it = m_IFunction.erase(it);
450
    }
451
    else
452
    {
453
454
455
456
      if (*it > i)
      {
        *it -= 1;
      }
457
      ++it;
458
459
460
461
462
    }
  }

  m_nParams -= dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
463
  for(size_t j=i+1;j<nFunctions();j++)
464
465
466
467
468
469
470
471
  {
    m_paramOffsets[j] -= dnp;
  }
  m_paramOffsets.erase(m_paramOffsets.begin()+i);

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

472
/** Replace a function with a new one. The old function is deleted.
473
 *  The new function must have already its workspace set.
474
 * @param f_old :: The pointer to the function to replace. If it's not
475
 *  a member of this composite function nothing happens
476
 * @param f_new :: A pointer to the new function
477
 */
478
void CompositeFunction::replaceFunctionPtr(const IFunction_sptr f_old,IFunction_sptr f_new)
479
{
480
  std::vector<IFunction_sptr>::const_iterator it = 
481
482
    std::find(m_functions.begin(),m_functions.end(),f_old);
  if (it == m_functions.end()) return;
483
  std::vector<IFunction_sptr>::difference_type iFun = it - m_functions.begin();
484
  replaceFunction(iFun,f_new);
485
486
}

487
/** Replace a function with a new one. The old function is deleted.
488
489
 * @param i :: The index of the function to replace
 * @param f :: A pointer to the new function
490
 */
491
void CompositeFunction::replaceFunction(size_t i,IFunction_sptr f)
492
{
493
  if ( i >= nFunctions() )
494
495
    throw std::out_of_range("Function index out of range.");

496
  IFunction_sptr fun = getFunction(i);
497
  size_t np_old = fun->nParams();
498

499
  size_t np_new = f->nParams();
500
501
502

  // Modify function indeces: The new function may have different number of parameters
  {
503
504
    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
505
    {
506
507
      if (np_old > np_new)
      {
508
        m_IFunction.erase(itFun,itFun + np_old - np_new);
509
510
511
      }
      else if (np_old < np_new) 
      {
512
        m_IFunction.insert(itFun,np_new - np_old,i);
513
      }
514
    }
515
516
    else if (np_new > 0) // it could happen if the old function is an empty CompositeFunction
    {
517
518
      itFun = std::find_if(m_IFunction.begin(),m_IFunction.end(),std::bind2nd(std::greater<size_t>(),i));
      m_IFunction.insert(itFun,np_new,i);
519
    }
520
521
  }

522
  size_t dnp = np_new - np_old;
523
524
  m_nParams += dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
525
  for(size_t j=i+1;j<nFunctions();j++)
526
527
528
529
530
531
532
  {
    m_paramOffsets[j] += dnp;
  }

  m_functions[i] = f;
}

533
/**
534
 * @param i :: The index of the function
535
 * @return function at the requested index
536
 */
537
IFunction_sptr CompositeFunction::getFunction(std::size_t i)const
538
{
Peterson, Peter's avatar
Peterson, Peter committed
539
  if ( i >= nFunctions() )
540
  {
541
    throw std::out_of_range("Function index out of range.");
542
  }
543
544
545
  return m_functions[i];
}

546
547
/**
 * Get the index of the function to which parameter i belongs
548
 * @param i :: The parameter index
549
 * @return function index of the requested parameter
550
 */
551
size_t CompositeFunction::functionIndex(std::size_t i)const
552
{
553
  if( i >= nParams() )
554
  {
555
    throw std::out_of_range("Function parameter index out of range.");
556
  }
557
  return m_IFunction[i];
558
559
560
}

/**
561
* @param varName :: The variable name which may contain function index ( [f<index.>]name )
562
* @param index :: Receives function index or throws std::invalid_argument
563
* @param name :: Receives the parameter name
564
*/
565
void CompositeFunction::parseName(const std::string& varName,size_t& index, std::string& name)
566
{
567
568
569
  size_t i = varName.find('.');
  if (i == std::string::npos)
  {
570
    throw std::invalid_argument("Parameter " + varName + " not found.");
571
572
573
574
575
576
  }
  else
  {
    if (varName[0] != 'f')
      throw std::invalid_argument("External function parameter name must start with 'f'");

577
    std::string sindex = varName.substr(1,i - 1);
578
579
580
581
582
583
584
    index = boost::lexical_cast<int>(sindex);

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

    name = varName.substr(i+1);
  }
585
586
}

587
/** Returns the index of parameter i as it declared in its function
588
 * @param i :: The parameter index
589
590
 * @return The local index of the parameter
 */
591
size_t CompositeFunction::parameterLocalIndex(size_t i)const
592
{
593
  size_t iFun = functionIndex(i);
594
595
596
  return i - m_paramOffsets[iFun];
}

597
/** Returns the name of parameter i as it declared in its function
598
 * @param i :: The parameter index
599
600
 * @return The pure parameter name (without the function identifier f#.)
 */
601
std::string CompositeFunction::parameterLocalName(size_t i)const
602
{
603
  size_t iFun = functionIndex(i);
604
605
606
  return m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
}

607
/**
608
 * Apply the ties.
609
610
611
 */
void CompositeFunction::applyTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
612
  for(size_t i=0;i<nFunctions();i++)
613
614
615
616
617
618
619
620
621
622
  {
    getFunction(i)->applyTies();
  }
}

/**
 * Clear the ties. 
 */
void CompositeFunction::clearTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
623
  for(size_t i=0;i<nFunctions();i++)
624
625
626
627
628
629
  {
    getFunction(i)->clearTies();
  }
}

/** Removes i-th parameter's tie if it is tied or does nothing.
630
 * @param i :: The index of the tied parameter.
631
632
 * @return True if successfull
 */
633
bool CompositeFunction::removeTie(size_t i)
634
{
635
  size_t iFun = functionIndex(i);
636
637
638
639
640
  bool res = m_functions[ iFun ]->removeTie(i - m_paramOffsets[iFun]);
  return res;
}

/** Get the tie of i-th parameter
641
 * @param i :: The parameter index
642
 * @return A pointer to the tie.
643
 */
644
ParameterTie* CompositeFunction::getTie(size_t i)const
645
{
646
  size_t iFun = functionIndex(i);
647
648
649
650
651
  return m_functions[ iFun ]->getTie(i - m_paramOffsets[iFun]);
}

/**
 * Attaches a tie to this function. The attached tie is owned by the function.
652
 * @param tie :: A pointer to a new tie
653
654
655
 */
void CompositeFunction::addTie(ParameterTie* tie)
{
656
657
  size_t i = getParameterIndex(*tie);
  size_t iFun = functionIndex(i);
658
659
660
661
662
  m_functions[iFun]->addTie(tie);
}

/**
 * Declare a new parameter. To used in the implementation'c constructor.
663
664
 * @param name :: The parameter name.
 * @param initValue :: The initial value for the parameter
665
 * @param description :: Parameter documentation
666
 */
667
void CompositeFunction::declareParameter(const std::string& name, double initValue, const std::string& description)
668
{
669
670
  (void) name; //Avoid compiler warning
  (void) initValue; //Avoid compiler warning
671
  (void) description; //Avoid compiler warning
672
673
674
675
  throw Kernel::Exception::NotImplementedError("CompositeFunction cannot not have its own parameters.");
}

/** Add a constraint
676
 *  @param ic :: Pointer to a constraint.
677
678
679
 */
void CompositeFunction::addConstraint(IConstraint* ic)
{
680
681
  size_t i = getParameterIndex(*ic);
  size_t iFun = functionIndex(i);
682
  getFunction(iFun)->addConstraint(ic);
683
684
}

685
686
687
/**
 * Prepare the function for a fit.
 */
688
void CompositeFunction::setUpForFit()
689
{
690
  // set up the member functions
Peterson, Peter's avatar
Peterson, Peter committed
691
  for(size_t i=0;i<nFunctions();i++)
692
  {
693
    getFunction(i)->setUpForFit();
694
  }
695
696
697
698
  // 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
  //
699
  // if parameters have non-constant ties enable numerical derivatives
700
701
702
703
704
705
706
707
708
709
710
711
712
  //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
  if ( !m_useNumericDerivatives ) 
713
  {
714
    for(size_t i = 0; i < nParams(); ++i)
715
    {
716
717
718
719
720
721
      ParameterTie* tie = getTie( i );
      if ( tie && !tie->isConstant() )
      {
        g_log.warning() << "Numeric derivatives should be used when non-constant ties defined." << std::endl;
        break;
      }
722
    }
723
724
725
  }
}

Nick Draper's avatar
re #100    
Nick Draper committed
726
/// Get constraint
727
/// @param i :: the index
Nick Draper's avatar
re #100    
Nick Draper committed
728
/// @return A pointer to the constraint
729
IConstraint* CompositeFunction::getConstraint(size_t i)const
730
{
731
  size_t iFun = functionIndex(i);
732
  return m_functions[ iFun ]->getConstraint(i - m_paramOffsets[iFun]);
733
734
}

735
/** Remove a constraint
736
 * @param parName :: The name of a parameter which constarint to remove.
737
738
739
 */
void CompositeFunction::removeConstraint(const std::string& parName)
{
740
741
  size_t iPar = parameterIndex(parName);
  size_t iFun = functionIndex(iPar);
742
743
744
  getFunction(iFun)->removeConstraint(parameterLocalName(iPar));
}

745
/** Checks if a constraint has been explicitly set
746
 *  @param i :: The parameter index
747
 *  @return true if the function is explicitly set
748
 */
749
bool CompositeFunction::isExplicitlySet(size_t i)const
750
{
751
  size_t iFun = functionIndex(i);
752
753
754
  return m_functions[ iFun ]->isExplicitlySet(i - m_paramOffsets[iFun]);
}

755
/**
756
 * Returns the index of parameter if the ref points to one of the member function
757
 * @param ref :: A reference to a parameter
758
 * @return Parameter index or number of nParams() if parameter not found
759
 */
760
size_t CompositeFunction::getParameterIndex(const ParameterReference& ref)const
761
{
762
  if (ref.getFunction() == this && ref.getIndex() < nParams())
763
  {
764
    return ref.getIndex();
765
  }
Peterson, Peter's avatar
Peterson, Peter committed
766
  for(size_t iFun=0;iFun<nFunctions();iFun++)
767
  {
768
    IFunction_sptr fun = getFunction(iFun);
769
770
    size_t iLocalIndex = fun->getParameterIndex(ref);
    if (iLocalIndex < fun->nParams())
771
772
773
774
    {
      return m_paramOffsets[iFun] + iLocalIndex;
    }
  }
775
  return nParams();
776
777
}

778
/**
779
 * Returns the shrared pointer to the function conataining a parameter
780
 * @param ref :: The reference
781
782
 * @return A function containing parameter pointed to by ref
 */
783
IFunction_sptr CompositeFunction::getContainingFunction(const ParameterReference& ref)const
784
{
Peterson, Peter's avatar
Peterson, Peter committed
785
  for(size_t iFun=0;iFun<nFunctions();iFun++)
786
  {
787
788
    IFunction_sptr fun = getFunction(iFun);
    if (fun->getParameterIndex(ref) < fun->nParams())
789
    {
790
      return fun;
791
792
    }
  }
793
794
795
  return IFunction_sptr();
}

796
797
798
799
800
801
802
803
804
/**
 * Enable/disable numeric derivative calculation.
 * @param yes :: Set to true to use numeric derivative calculation.
 */
void CompositeFunction::useNumericDerivatives( bool yes ) const
{
  m_useNumericDerivatives = yes;
}

805
806
807
808
809
810
811
812
813
814
/// Set a value to attribute attName
void CompositeFunction::setAttribute(const std::string& attName,const Attribute& att)
{
  storeAttributeValue( attName, att );

  if ( attName == "NumDeriv" )
  {
    useNumericDerivatives( att.asBool() );
  }
}
815

816
817
} // namespace API
} // namespace Mantid