CompositeFunction.cpp 22.2 KB
Newer Older
1
2
3
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
4
5
#include "MantidAPI/CompositeFunction.h"
#include "MantidAPI/ParameterTie.h"
6
#include "MantidAPI/IConstraint.h"
7
#include "MantidAPI/FunctionFactory.h"
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
8
9
10
#include "MantidKernel/Exception.h"
#include "MantidKernel/Logger.h"

11
#include <boost/lexical_cast.hpp>
12
13
#include <boost/shared_array.hpp>
#include <sstream>
14
#include <algorithm>
15

16
17
namespace Mantid {
namespace API {
18

19
20
21
22
namespace {
/// static logger
Kernel::Logger g_log("CompositeFunction");
}
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
23

Peterson, Peter's avatar
Peterson, Peter committed
24
25
using std::size_t;

26
DECLARE_FUNCTION(CompositeFunction)
27

28
/// Default constructor
29
30
CompositeFunction::CompositeFunction()
    : IFunction(), m_nParams(0), m_iConstraintFunction(false) {
31
32
33
  declareAttribute("NumDeriv", Attribute(false));
}

34
35
/// Destructor
CompositeFunction::~CompositeFunction() {}
36
37

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

40
/**
41
42
43
44
45
46
47
48
49
50
 * 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=(" << ... <<")";
 *   }
51
 * @return the string representation of the composite function
52
 */
53
std::string CompositeFunction::asString() const {
54
  std::ostringstream ostr;
55

56
  // if empty just return function name
57
  if (nFunctions() == 0) {
58
59
60
    return "name=" + name();
  }

61
62
63
  if (name() != "CompositeFunction" || nAttributes() > 1 ||
      getAttribute("NumDeriv").asBool() == true) {
    ostr << "composite=" << name();
64
    std::vector<std::string> attr = this->getAttributeNames();
65
66
67
    for (auto &i : attr) {
      std::string attName = i;
      std::string attValue = this->getAttribute(i).value();
68
69
      if (!attValue.empty()) {
        ostr << ',' << attName << '=' << attValue;
70
71
72
      }
    }
    ostr << ';';
73
  }
74
  for (size_t i = 0; i < nFunctions(); i++) {
75
76
    IFunction_sptr fun = getFunction(i);
    bool isComp = boost::dynamic_pointer_cast<CompositeFunction>(fun) != 0;
77
78
    if (isComp)
      ostr << '(';
79
    ostr << fun->asString();
80
81
82
    if (isComp)
      ostr << ')';
    if (i < nFunctions() - 1) {
83
84
85
86
      ostr << ';';
    }
  }
  std::string ties;
87
88
89
  for (size_t i = 0; i < nParams(); i++) {
    const ParameterTie *tie = getTie(i);
    if (tie) {
90
91
      IFunction_sptr fun = getFunction(functionIndex(i));
      std::string tmp = tie->asString(fun.get());
92
      if (tmp.empty()) {
93
        tmp = tie->asString(this);
94
95
        if (!tmp.empty()) {
          if (!ties.empty()) {
96
97
98
99
100
101
102
            ties += ",";
          }
          ties += tmp;
        }
      }
    }
  }
103
  if (!ties.empty()) {
104
    ostr << ";ties=(" << ties << ")";
105
106
107
108
  }
  return ostr.str();
}

109
110
111
/**
 * @param ws A pointer to the workspace being fitted
 */
112
void CompositeFunction::setWorkspace(boost::shared_ptr<const Workspace> ws) {
113
114
  // Pass it on to each member
  auto iend = m_functions.end();
115
  for (auto it = m_functions.begin(); it != iend; ++it) {
116
117
118
119
    (*it)->setWorkspace(ws);
  }
}

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

134
/** Function you want to fit to.
135
 *  @param domain :: An instance of FunctionDomain with the function arguments.
136
137
 *  @param values :: A FunctionValues instance for storing the calculated
 * values.
138
 */
139
140
void CompositeFunction::function(const FunctionDomain &domain,
                                 FunctionValues &values) const {
141
  FunctionValues tmp(domain);
142
  values.zeroCalculated();
143
144
  for (size_t iFun = 0; iFun < nFunctions(); ++iFun) {
    m_functions[iFun]->function(domain, tmp);
145
146
147
148
149
150
151
152
153
    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.
 */
154
155
156
void CompositeFunction::functionDeriv(const FunctionDomain &domain,
                                      Jacobian &jacobian) {
  if (getAttribute("NumDeriv").asBool()) {
157
    calNumericalDeriv(domain, jacobian);
158
159
160
161
  } else {
    for (size_t iFun = 0; iFun < nFunctions(); ++iFun) {
      PartialJacobian J(&jacobian, paramOffset(iFun));
      getFunction(iFun)->functionDeriv(domain, J);
162
    }
163
164
165
  }
}

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

179
180
181
182
/** Sets a new description to the i-th parameter.
 *  @param i :: The parameter index
 *  @param description :: The new description
 */
183
184
void CompositeFunction::setParameterDescription(
    size_t i, const std::string &description) {
185
  size_t iFun = functionIndex(i);
186
187
  m_functions[iFun]->setParameterDescription(i - m_paramOffsets[iFun],
                                             description);
188
189
}

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

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

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

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

/// Total number of parameters
240
size_t CompositeFunction::nParams() const { return m_nParams; }
241

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

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

265
266
267
/// Returns the description of parameter
/// @param i :: The index
/// @return The description of the parameter
268
std::string CompositeFunction::parameterDescription(size_t i) const {
269
  size_t iFun = functionIndex(i);
270
  std::ostringstream ostr;
271
  ostr << m_functions[iFun]->parameterDescription(i - m_paramOffsets[iFun]);
272
273
274
  return ostr.str();
}

275
/**
276
277
278
279
 * Get the fitting error for a parameter
 * @param i :: The index of a parameter
 * @return :: the error
 */
280
double CompositeFunction::getError(size_t i) const {
281
  size_t iFun = functionIndex(i);
282
  return m_functions[iFun]->getError(i - m_paramOffsets[iFun]);
283
284
}

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

295
296
297
/// Value of i-th active parameter. Override this method to make fitted
/// parameters different from the declared
double CompositeFunction::activeParameter(size_t i) const {
298
  size_t iFun = functionIndex(i);
299
  return m_functions[iFun]->activeParameter(i - m_paramOffsets[iFun]);
300
301
}

302
303
304
/// Set new value of i-th active parameter. Override this method to make fitted
/// parameters different from the declared
void CompositeFunction::setActiveParameter(size_t i, double value) {
305
  size_t iFun = functionIndex(i);
306
  m_functions[iFun]->setActiveParameter(i - m_paramOffsets[iFun], value);
307
308
309
}

/// Returns the name of active parameter i
310
std::string CompositeFunction::nameOfActive(size_t i) const {
311
  size_t iFun = functionIndex(i);
312
  std::ostringstream ostr;
313
314
  ostr << 'f' << iFun << '.'
       << m_functions[iFun]->nameOfActive(i - m_paramOffsets[iFun]);
315
316
317
318
  return ostr.str();
}

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

326
327
328
329
330
/**
 * query to see in the function is active
 * @param i :: The index of a declared parameter
 * @return true if parameter i is active
 */
331
bool CompositeFunction::isActive(size_t i) const {
332
  size_t iFun = functionIndex(i);
333
  return m_functions[iFun]->isActive(i - m_paramOffsets[iFun]);
334
335
}

336
/**
337
 * query to see in the function is active
338
 * @param i :: The index of a declared parameter
339
 * @return true if parameter i is active
340
 */
341
bool CompositeFunction::isFixed(size_t i) const {
342
  size_t iFun = functionIndex(i);
343
  return m_functions[iFun]->isFixed(i - m_paramOffsets[iFun]);
344
345
346
}

/**
347
 * @param i :: A declared parameter index to be removed from active
348
 */
349
void CompositeFunction::fix(size_t i) {
350
  size_t iFun = functionIndex(i);
351
  m_functions[iFun]->fix(i - m_paramOffsets[iFun]);
352
353
}

354
/** Makes a parameter active again. It doesn't change the parameter's tie.
355
 * @param i :: A declared parameter index to be restored to active
356
 */
357
void CompositeFunction::unfix(size_t i) {
358
  size_t iFun = functionIndex(i);
359
  m_functions[iFun]->unfix(i - m_paramOffsets[iFun]);
360
361
}

362
/** Makes sure that the function is consistent.
363
 */
364
void CompositeFunction::checkFunction() {
365
366
  m_nParams = 0;
  m_paramOffsets.clear();
367
  m_IFunction.clear();
368

369
  std::vector<IFunction_sptr> functions(m_functions.begin(), m_functions.end());
370
371
  m_functions.clear();

372
  for (auto f : functions) {
373
374
375
376
    CompositeFunction_sptr cf =
        boost::dynamic_pointer_cast<CompositeFunction>(f);
    if (cf)
      cf->checkFunction();
377
378
379
380
    addFunction(f);
  }
}

381
/** Add a function
382
 * @param f :: A pointer to the added function
383
 * @return The function index
384
 */
385
386
size_t CompositeFunction::addFunction(IFunction_sptr f) {
  m_IFunction.insert(m_IFunction.end(), f->nParams(), m_functions.size());
387
388
  m_functions.push_back(f);
  //?f->init();
389
  if (m_paramOffsets.size() == 0) {
390
391
    m_paramOffsets.push_back(0);
    m_nParams = f->nParams();
392
  } else {
393
394
395
    m_paramOffsets.push_back(m_nParams);
    m_nParams += f->nParams();
  }
396
  return m_functions.size() - 1;
397
398
}

399
/** Remove a function
400
 * @param i :: The index of the function to remove
401
 */
402
403
void CompositeFunction::removeFunction(size_t i) {
  if (i >= nFunctions())
404
405
    throw std::out_of_range("Function index out of range.");

406
  IFunction_sptr fun = getFunction(i);
407

408
  size_t dnp = fun->nParams();
409

410
411
412
  for (size_t j = 0; j < nParams();) {
    ParameterTie *tie = getTie(j);
    if (tie && tie->findParametersOf(fun.get())) {
413
      removeTie(j);
414
    } else {
415
416
417
418
419
      j++;
    }
  }

  // Shift down the function indeces for parameters
420
  for (auto it = m_IFunction.begin(); it != m_IFunction.end();) {
421

422
    if (*it == i) {
423
      it = m_IFunction.erase(it);
424
425
    } else {
      if (*it > i) {
426
427
        *it -= 1;
      }
428
      ++it;
429
430
431
432
    }
  }

  m_nParams -= dnp;
433
434
435
  // Shift the parameter offsets down by the total number of i-th function's
  // params
  for (size_t j = i + 1; j < nFunctions(); j++) {
436
437
    m_paramOffsets[j] -= dnp;
  }
438
  m_paramOffsets.erase(m_paramOffsets.begin() + i);
439

440
  m_functions.erase(m_functions.begin() + i);
441
442
}

443
/** Replace a function with a new one. The old function is deleted.
444
 *  The new function must have already its workspace set.
445
 * @param f_old :: The pointer to the function to replace. If it's not
446
 *  a member of this composite function nothing happens
447
 * @param f_new :: A pointer to the new function
448
 */
449
450
451
452
453
454
void CompositeFunction::replaceFunctionPtr(const IFunction_sptr f_old,
                                           IFunction_sptr f_new) {
  std::vector<IFunction_sptr>::const_iterator it =
      std::find(m_functions.begin(), m_functions.end(), f_old);
  if (it == m_functions.end())
    return;
455
  std::vector<IFunction_sptr>::difference_type iFun = it - m_functions.begin();
456
  replaceFunction(iFun, f_new);
457
458
}

459
/** Replace a function with a new one. The old function is deleted.
460
461
 * @param i :: The index of the function to replace
 * @param f :: A pointer to the new function
462
 */
463
464
void CompositeFunction::replaceFunction(size_t i, IFunction_sptr f) {
  if (i >= nFunctions())
465
466
    throw std::out_of_range("Function index out of range.");

467
  IFunction_sptr fun = getFunction(i);
468
  size_t np_old = fun->nParams();
469

470
  size_t np_new = f->nParams();
471

472
473
  // Modify function indeces: The new function may have different number of
  // parameters
474
  {
475
    auto itFun = std::find(m_IFunction.begin(), m_IFunction.end(), i);
476
    if (itFun != m_IFunction.end()) // functions must have at least 1 parameter
477
    {
478
479
480
481
      if (np_old > np_new) {
        m_IFunction.erase(itFun, itFun + np_old - np_new);
      } else if (np_old < np_new) {
        m_IFunction.insert(itFun, np_new - np_old, i);
482
      }
483
484
    } else if (np_new > 0) // it could happen if the old function is an empty
                           // CompositeFunction
485
    {
486
487
488
      itFun = std::find_if(m_IFunction.begin(), m_IFunction.end(),
                           std::bind2nd(std::greater<size_t>(), i));
      m_IFunction.insert(itFun, np_new, i);
489
    }
490
491
  }

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

  m_functions[i] = f;
}

503
/**
504
 * @param i :: The index of the function
505
 * @return function at the requested index
506
 */
507
508
IFunction_sptr CompositeFunction::getFunction(std::size_t i) const {
  if (i >= nFunctions()) {
509
    throw std::out_of_range("Function index out of range.");
510
  }
511
512
513
  return m_functions[i];
}

514
515
/**
 * Get the index of the function to which parameter i belongs
516
 * @param i :: The parameter index
517
 * @return function index of the requested parameter
518
 */
519
520
size_t CompositeFunction::functionIndex(std::size_t i) const {
  if (i >= nParams()) {
521
    throw std::out_of_range("Function parameter index out of range.");
522
  }
523
  return m_IFunction[i];
524
525
526
}

/**
527
528
* @param varName :: The variable name which may contain function index (
* [f<index.>]name )
529
* @param index :: Receives function index or throws std::invalid_argument
530
* @param name :: Receives the parameter name
531
*/
532
533
void CompositeFunction::parseName(const std::string &varName, size_t &index,
                                  std::string &name) {
534
  size_t i = varName.find('.');
535
  if (i == std::string::npos) {
536
    throw std::invalid_argument("Parameter " + varName + " not found.");
537
  } else {
538
    if (varName[0] != 'f')
539
540
      throw std::invalid_argument(
          "External function parameter name must start with 'f'");
541

542
    std::string sindex = varName.substr(1, i - 1);
543
544
545
546
547
    index = boost::lexical_cast<int>(sindex);

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

548
    name = varName.substr(i + 1);
549
  }
550
551
}

552
/** Returns the index of parameter i as it declared in its function
553
 * @param i :: The parameter index
554
555
 * @return The local index of the parameter
 */
556
size_t CompositeFunction::parameterLocalIndex(size_t i) const {
557
  size_t iFun = functionIndex(i);
558
559
560
  return i - m_paramOffsets[iFun];
}

561
/** Returns the name of parameter i as it declared in its function
562
 * @param i :: The parameter index
563
564
 * @return The pure parameter name (without the function identifier f#.)
 */
565
std::string CompositeFunction::parameterLocalName(size_t i) const {
566
  size_t iFun = functionIndex(i);
567
  return m_functions[iFun]->parameterName(i - m_paramOffsets[iFun]);
568
569
}

570
/**
571
 * Apply the ties.
572
 */
573
574
void CompositeFunction::applyTies() {
  for (size_t i = 0; i < nFunctions(); i++) {
575
576
577
578
579
    getFunction(i)->applyTies();
  }
}

/**
580
 * Clear the ties.
581
 */
582
583
void CompositeFunction::clearTies() {
  for (size_t i = 0; i < nFunctions(); i++) {
584
585
586
587
588
    getFunction(i)->clearTies();
  }
}

/** Removes i-th parameter's tie if it is tied or does nothing.
589
 * @param i :: The index of the tied parameter.
590
591
 * @return True if successfull
 */
592
bool CompositeFunction::removeTie(size_t i) {
593
  size_t iFun = functionIndex(i);
594
  bool res = m_functions[iFun]->removeTie(i - m_paramOffsets[iFun]);
595
596
597
598
  return res;
}

/** Get the tie of i-th parameter
599
 * @param i :: The parameter index
600
 * @return A pointer to the tie.
601
 */
602
ParameterTie *CompositeFunction::getTie(size_t i) const {
603
  size_t iFun = functionIndex(i);
604
  return m_functions[iFun]->getTie(i - m_paramOffsets[iFun]);
605
606
607
608
}

/**
 * Attaches a tie to this function. The attached tie is owned by the function.
609
 * @param tie :: A pointer to a new tie
610
 */
611
void CompositeFunction::addTie(ParameterTie *tie) {
612
613
  size_t i = getParameterIndex(*tie);
  size_t iFun = functionIndex(i);
614
615
616
617
618
  m_functions[iFun]->addTie(tie);
}

/**
 * Declare a new parameter. To used in the implementation'c constructor.
619
620
 * @param name :: The parameter name.
 * @param initValue :: The initial value for the parameter
621
 * @param description :: Parameter documentation
622
 */
623
624
625
626
627
628
629
630
void CompositeFunction::declareParameter(const std::string &name,
                                         double initValue,
                                         const std::string &description) {
  (void)name;        // Avoid compiler warning
  (void)initValue;   // Avoid compiler warning
  (void)description; // Avoid compiler warning
  throw Kernel::Exception::NotImplementedError(
      "CompositeFunction cannot not have its own parameters.");
631
632
633
}

/** Add a constraint
634
 *  @param ic :: Pointer to a constraint.
635
 */
636
void CompositeFunction::addConstraint(IConstraint *ic) {
637
638
  size_t i = getParameterIndex(*ic);
  size_t iFun = functionIndex(i);
639
  getFunction(iFun)->addConstraint(ic);
640
641
}

642
643
644
/**
 * Prepare the function for a fit.
 */
645
void CompositeFunction::setUpForFit() {
646
  // set up the member functions
647
  for (size_t i = 0; i < nFunctions(); i++) {
648
    getFunction(i)->setUpForFit();
649
  }
650
651
652
653
  // 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
  //
654
  // if parameters have non-constant ties enable numerical derivatives
655
  // for(size_t i = 0; i < nParams(); ++i)
656
657
658
659
660
661
662
663
664
665
666
  //{
  //  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
667
668
669
670
671
672
  if (!getAttribute("NumDeriv").asBool()) {
    for (size_t i = 0; i < nParams(); ++i) {
      ParameterTie *tie = getTie(i);
      if (tie && !tie->isConstant()) {
        g_log.warning() << "Numeric derivatives should be used when "
                           "non-constant ties defined." << std::endl;
673
674
        break;
      }
675
    }
676
677
678
  }
}

Nick Draper's avatar
re #100    
Nick Draper committed
679
/// Get constraint
680
/// @param i :: the index
Nick Draper's avatar
re #100    
Nick Draper committed
681
/// @return A pointer to the constraint
682
IConstraint *CompositeFunction::getConstraint(size_t i) const {
683
  size_t iFun = functionIndex(i);
684
  return m_functions[iFun]->getConstraint(i - m_paramOffsets[iFun]);
685
686
}

687
/** Remove a constraint
688
 * @param parName :: The name of a parameter which constarint to remove.
689
 */
690
void CompositeFunction::removeConstraint(const std::string &parName) {
691
692
  size_t iPar = parameterIndex(parName);
  size_t iFun = functionIndex(iPar);
693
694
695
  getFunction(iFun)->removeConstraint(parameterLocalName(iPar));
}

696
/** Checks if a constraint has been explicitly set
697
 *  @param i :: The parameter index
698
 *  @return true if the function is explicitly set
699
 */
700
bool CompositeFunction::isExplicitlySet(size_t i) const {
701
  size_t iFun = functionIndex(i);
702
  return m_functions[iFun]->isExplicitlySet(i - m_paramOffsets[iFun]);
703
704
}

705
/**
706
707
 * Returns the index of parameter if the ref points to one of the member
 * function
708
 * @param ref :: A reference to a parameter
709
 * @return Parameter index or number of nParams() if parameter not found
710
 */
711
712
713
size_t
CompositeFunction::getParameterIndex(const ParameterReference &ref) const {
  if (ref.getFunction() == this && ref.getIndex() < nParams()) {
714
    return ref.getIndex();
715
  }
716
  for (size_t iFun = 0; iFun < nFunctions(); iFun++) {
717
    IFunction_sptr fun = getFunction(iFun);
718
    size_t iLocalIndex = fun->getParameterIndex(ref);
719
    if (iLocalIndex < fun->nParams()) {
720
721
722
      return m_paramOffsets[iFun] + iLocalIndex;
    }
  }
723
  return nParams();
724
725
}

726
/**
727
 * Returns the shrared pointer to the function conataining a parameter
728
 * @param ref :: The reference
729
730
 * @return A function containing parameter pointed to by ref
 */
731
732
733
IFunction_sptr
CompositeFunction::getContainingFunction(const ParameterReference &ref) const {
  for (size_t iFun = 0; iFun < nFunctions(); iFun++) {
734
    IFunction_sptr fun = getFunction(iFun);
735
    if (fun->getParameterIndex(ref) < fun->nParams()) {
736
      return fun;
737
738
    }
  }
739
740
741
  return IFunction_sptr();
}

742
743
} // namespace API
} // namespace Mantid