CompositeFunction.cpp 21.5 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
/** 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);
128
  values.zeroCalculated();
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  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)
{
143
144
145
146
147
  if ( m_useNumericDerivatives )
  {
    calNumericalDeriv(domain, jacobian);
  }
  else
148
  {
149
150
151
152
153
    for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
    {
      PartialJacobian J(&jacobian,paramOffset(iFun));
      getFunction(iFun)->functionDeriv(domain,J);
    }
154
155
156
  }
}

157
/** Sets a new value to the i-th parameter.
158
159
160
 *  @param i :: The parameter index
 *  @param value :: The new value
 *  @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
161
 */
162
void CompositeFunction::setParameter(size_t i, const double& value, bool explicitlySet)
163
{
164
  size_t iFun = functionIndex(i);
165
  m_functions[ iFun ]->setParameter(i - m_paramOffsets[iFun],value,explicitlySet);
166
167
}

168
169
170
171
172
173
/** 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)
{
174
  size_t iFun = functionIndex(i);
175
176
177
  m_functions[ iFun ]->setParameterDescription(i - m_paramOffsets[iFun],description);
}

178
/** Get the i-th parameter.
179
 *  @param i :: The parameter index
180
 *  @return value of the requested parameter
181
 */
182
double CompositeFunction::getParameter(size_t i)const
183
{
Peterson, Peter's avatar
Peterson, Peter committed
184
  size_t iFun = functionIndex(i);
185
  return m_functions[ iFun ]->getParameter(i - m_paramOffsets[iFun]);
186
187
}

188
189
/**
 * Sets a new value to a parameter by name.
190
191
192
 * @param name :: The name of the parameter.
 * @param value :: The new value
 * @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
193
194
 */
void CompositeFunction::setParameter(const std::string& name, const double& value, bool explicitlySet)
195
{
196
  std::string pname;
197
  size_t index;
198
  parseName(name,index,pname);
199
  getFunction(index)->setParameter(pname,value,explicitlySet);
200
201
}

202
203
204
/**
 * Sets a new description to a parameter by name.
 * @param name :: The name of the parameter.
205
 * @param description :: The new description
206
207
208
209
 */
void CompositeFunction::setParameterDescription(const std::string& name, const std::string& description)
{
  std::string pname;
210
  size_t index;
211
  parseName(name,index,pname);
212
  getFunction(index)->setParameterDescription(pname,description);
213
214
}

215
216
/**
 * Parameters by name.
217
 * @param name :: The name of the parameter.
218
 * @return value of the requested named parameter
219
 */
220
221
double CompositeFunction::getParameter(const std::string& name)const
{
222
  std::string pname;
223
  size_t index;
224
  parseName(name,index,pname);
225
  return getFunction(index)->getParameter(pname);
226
227
228
}

/// Total number of parameters
229
size_t CompositeFunction::nParams()const
230
231
232
233
{
  return m_nParams;
}

234
/**
235
 * 
236
 * @param name :: The name of a parameter
237
 * @return index of the requested named parameter
238
 */
239
size_t CompositeFunction::parameterIndex(const std::string& name)const
240
{
241
  std::string pname;
242
  size_t index;
243
  parseName(name,index,pname);
244
  return getFunction(index)->parameterIndex(pname) + m_paramOffsets[index];
245
246
}

Nick Draper's avatar
re #100    
Nick Draper committed
247
/// Returns the name of parameter
248
/// @param i :: The index
Nick Draper's avatar
re #100    
Nick Draper committed
249
/// @return The name of the parameter
250
std::string CompositeFunction::parameterName(size_t i)const
251
{
252
  size_t iFun = functionIndex(i);
253
254
255
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
  return ostr.str();
256
257
}

258
259
260
261
262
/// Returns the description of parameter
/// @param i :: The index
/// @return The description of the parameter
std::string CompositeFunction::parameterDescription(size_t i)const
{
263
  size_t iFun = functionIndex(i);
264
265
266
267
268
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->parameterDescription(i - m_paramOffsets[iFun]);
  return ostr.str();
}

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
/** 
 * 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);
}

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

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

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

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

323
324
325
326
327
328
329
330
331
332
333
/**
 * 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]);
}

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

/**
346
 * @param i :: A declared parameter index to be removed from active
347
 */
348
void CompositeFunction::fix(size_t i)
349
{
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
{
359
  size_t iFun = functionIndex(i);
360
  m_functions[ iFun ]->unfix(i - m_paramOffsets[iFun]);
361
362
}

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

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

374
  for(std::vector<IFunction_sptr>::size_type i=0;i<functions.size();i++)
375
  {
376
377
    IFunction_sptr f = functions[i];
    CompositeFunction_sptr cf = boost::dynamic_pointer_cast<CompositeFunction>(f);
378
    if (cf) cf->checkFunction();
379
380
381
382
    addFunction(f);
  }
}

383
/** Add a function
384
 * @param f :: A pointer to the added function
385
 * @return The function index
386
 */
387
size_t CompositeFunction::addFunction(IFunction_sptr f)
388
{
389
  m_IFunction.insert(m_IFunction.end(),f->nParams(), m_functions.size());
390
391
392
393
394
395
396
397
398
399
400
401
  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();
  }
402
  return m_functions.size() - 1;
403
404
}

405
/** Remove a function
406
407
 * @param i :: The index of the function to remove
 * @param del :: The deletion flag. If true the function will be deleted otherwise - simply detached
408
 */
409
void CompositeFunction::removeFunction(size_t i)
410
{
411
  if ( i >= nFunctions() )
412
413
    throw std::out_of_range("Function index out of range.");

414
  IFunction_sptr fun = getFunction(i);
415

416
  size_t dnp = fun->nParams();
417

418
  for(size_t j=0;j<nParams();)
419
420
  {
    ParameterTie* tie = getTie(j);
421
    if (tie && tie->findParametersOf(fun.get()))
422
423
424
425
426
427
428
429
430
431
    {
      removeTie(j);
    }
    else
    {
      j++;
    }
  }

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

435
436
    if (*it == i)
    {
437
      it = m_IFunction.erase(it);
438
    }
439
    else
440
    {
441
442
443
444
      if (*it > i)
      {
        *it -= 1;
      }
445
      ++it;
446
447
448
449
450
    }
  }

  m_nParams -= dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
451
  for(size_t j=i+1;j<nFunctions();j++)
452
453
454
455
456
457
458
459
  {
    m_paramOffsets[j] -= dnp;
  }
  m_paramOffsets.erase(m_paramOffsets.begin()+i);

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

460
/** Replace a function with a new one. The old function is deleted.
461
 *  The new function must have already its workspace set.
462
 * @param f_old :: The pointer to the function to replace. If it's not
463
 *  a member of this composite function nothing happens
464
 * @param f_new :: A pointer to the new function
465
 */
466
void CompositeFunction::replaceFunctionPtr(const IFunction_sptr f_old,IFunction_sptr f_new)
467
{
468
  std::vector<IFunction_sptr>::const_iterator it = 
469
470
    std::find(m_functions.begin(),m_functions.end(),f_old);
  if (it == m_functions.end()) return;
471
  std::vector<IFunction_sptr>::difference_type iFun = it - m_functions.begin();
472
  replaceFunction(iFun,f_new);
473
474
}

475
/** Replace a function with a new one. The old function is deleted.
476
477
 * @param i :: The index of the function to replace
 * @param f :: A pointer to the new function
478
 */
479
void CompositeFunction::replaceFunction(size_t i,IFunction_sptr f)
480
{
481
  if ( i >= nFunctions() )
482
483
    throw std::out_of_range("Function index out of range.");

484
  IFunction_sptr fun = getFunction(i);
485
  size_t np_old = fun->nParams();
486

487
  size_t np_new = f->nParams();
488
489
490

  // Modify function indeces: The new function may have different number of parameters
  {
491
492
    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
493
    {
494
495
      if (np_old > np_new)
      {
496
        m_IFunction.erase(itFun,itFun + np_old - np_new);
497
498
499
      }
      else if (np_old < np_new) 
      {
500
        m_IFunction.insert(itFun,np_new - np_old,i);
501
      }
502
    }
503
504
    else if (np_new > 0) // it could happen if the old function is an empty CompositeFunction
    {
505
506
      itFun = std::find_if(m_IFunction.begin(),m_IFunction.end(),std::bind2nd(std::greater<size_t>(),i));
      m_IFunction.insert(itFun,np_new,i);
507
    }
508
509
  }

510
  size_t dnp = np_new - np_old;
511
512
  m_nParams += dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
513
  for(size_t j=i+1;j<nFunctions();j++)
514
515
516
517
518
519
520
  {
    m_paramOffsets[j] += dnp;
  }

  m_functions[i] = f;
}

521
/**
522
 * @param i :: The index of the function
523
 * @return function at the requested index
524
 */
525
IFunction_sptr CompositeFunction::getFunction(std::size_t i)const
526
{
Peterson, Peter's avatar
Peterson, Peter committed
527
  if ( i >= nFunctions() )
528
  {
529
    throw std::out_of_range("Function index out of range.");
530
  }
531
532
533
  return m_functions[i];
}

534
535
/**
 * Get the index of the function to which parameter i belongs
536
 * @param i :: The parameter index
537
 * @return function index of the requested parameter
538
 */
539
size_t CompositeFunction::functionIndex(std::size_t i)const
540
{
541
  if( i >= nParams() )
542
  {
543
    throw std::out_of_range("Function parameter index out of range.");
544
  }
545
  return m_IFunction[i];
546
547
548
}

/**
549
* @param varName :: The variable name which may contain function index ( [f<index.>]name )
550
* @param index :: Receives function index or throws std::invalid_argument
551
* @param name :: Receives the parameter name
552
*/
553
void CompositeFunction::parseName(const std::string& varName,size_t& index, std::string& name)
554
{
555
556
557
  size_t i = varName.find('.');
  if (i == std::string::npos)
  {
558
    throw std::invalid_argument("Parameter " + varName + " not found.");
559
560
561
562
563
564
  }
  else
  {
    if (varName[0] != 'f')
      throw std::invalid_argument("External function parameter name must start with 'f'");

565
    std::string sindex = varName.substr(1,i - 1);
566
567
568
569
570
571
572
    index = boost::lexical_cast<int>(sindex);

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

    name = varName.substr(i+1);
  }
573
574
}

575
/** Returns the index of parameter i as it declared in its function
576
 * @param i :: The parameter index
577
578
 * @return The local index of the parameter
 */
579
size_t CompositeFunction::parameterLocalIndex(size_t i)const
580
{
581
  size_t iFun = functionIndex(i);
582
583
584
  return i - m_paramOffsets[iFun];
}

585
/** Returns the name of parameter i as it declared in its function
586
 * @param i :: The parameter index
587
588
 * @return The pure parameter name (without the function identifier f#.)
 */
589
std::string CompositeFunction::parameterLocalName(size_t i)const
590
{
591
  size_t iFun = functionIndex(i);
592
593
594
  return m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
}

595
/**
596
 * Apply the ties.
597
598
599
 */
void CompositeFunction::applyTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
600
  for(size_t i=0;i<nFunctions();i++)
601
602
603
604
605
606
607
608
609
610
  {
    getFunction(i)->applyTies();
  }
}

/**
 * Clear the ties. 
 */
void CompositeFunction::clearTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
611
  for(size_t i=0;i<nFunctions();i++)
612
613
614
615
616
617
  {
    getFunction(i)->clearTies();
  }
}

/** Removes i-th parameter's tie if it is tied or does nothing.
618
 * @param i :: The index of the tied parameter.
619
620
 * @return True if successfull
 */
621
bool CompositeFunction::removeTie(size_t i)
622
{
623
  size_t iFun = functionIndex(i);
624
625
626
627
628
  bool res = m_functions[ iFun ]->removeTie(i - m_paramOffsets[iFun]);
  return res;
}

/** Get the tie of i-th parameter
629
 * @param i :: The parameter index
630
 * @return A pointer to the tie.
631
 */
632
ParameterTie* CompositeFunction::getTie(size_t i)const
633
{
634
  size_t iFun = functionIndex(i);
635
636
637
638
639
  return m_functions[ iFun ]->getTie(i - m_paramOffsets[iFun]);
}

/**
 * Attaches a tie to this function. The attached tie is owned by the function.
640
 * @param tie :: A pointer to a new tie
641
642
643
 */
void CompositeFunction::addTie(ParameterTie* tie)
{
644
645
  size_t i = getParameterIndex(*tie);
  size_t iFun = functionIndex(i);
646
647
648
649
650
  m_functions[iFun]->addTie(tie);
}

/**
 * Declare a new parameter. To used in the implementation'c constructor.
651
652
 * @param name :: The parameter name.
 * @param initValue :: The initial value for the parameter
653
 * @param description :: Parameter documentation
654
 */
655
void CompositeFunction::declareParameter(const std::string& name, double initValue, const std::string& description)
656
{
657
658
  (void) name; //Avoid compiler warning
  (void) initValue; //Avoid compiler warning
659
  (void) description; //Avoid compiler warning
660
661
662
663
  throw Kernel::Exception::NotImplementedError("CompositeFunction cannot not have its own parameters.");
}

/** Add a constraint
664
 *  @param ic :: Pointer to a constraint.
665
666
667
 */
void CompositeFunction::addConstraint(IConstraint* ic)
{
668
669
  size_t i = getParameterIndex(*ic);
  size_t iFun = functionIndex(i);
670
  getFunction(iFun)->addConstraint(ic);
671
672
}

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

Nick Draper's avatar
re #100    
Nick Draper committed
714
/// Get constraint
715
/// @param i :: the index
Nick Draper's avatar
re #100    
Nick Draper committed
716
/// @return A pointer to the constraint
717
IConstraint* CompositeFunction::getConstraint(size_t i)const
718
{
719
  size_t iFun = functionIndex(i);
720
  return m_functions[ iFun ]->getConstraint(i - m_paramOffsets[iFun]);
721
722
}

723
/** Remove a constraint
724
 * @param parName :: The name of a parameter which constarint to remove.
725
726
727
 */
void CompositeFunction::removeConstraint(const std::string& parName)
{
728
729
  size_t iPar = parameterIndex(parName);
  size_t iFun = functionIndex(iPar);
730
731
732
  getFunction(iFun)->removeConstraint(parameterLocalName(iPar));
}

733
/** Checks if a constraint has been explicitly set
734
 *  @param i :: The parameter index
735
 *  @return true if the function is explicitly set
736
 */
737
bool CompositeFunction::isExplicitlySet(size_t i)const
738
{
739
  size_t iFun = functionIndex(i);
740
741
742
  return m_functions[ iFun ]->isExplicitlySet(i - m_paramOffsets[iFun]);
}

743
/**
744
 * Returns the index of parameter if the ref points to one of the member function
745
 * @param ref :: A reference to a parameter
746
 * @return Parameter index or number of nParams() if parameter not found
747
 */
748
size_t CompositeFunction::getParameterIndex(const ParameterReference& ref)const
749
{
750
  if (ref.getFunction() == this && ref.getIndex() < nParams())
751
  {
752
    return ref.getIndex();
753
  }
Peterson, Peter's avatar
Peterson, Peter committed
754
  for(size_t iFun=0;iFun<nFunctions();iFun++)
755
  {
756
    IFunction_sptr fun = getFunction(iFun);
757
758
    size_t iLocalIndex = fun->getParameterIndex(ref);
    if (iLocalIndex < fun->nParams())
759
760
761
762
    {
      return m_paramOffsets[iFun] + iLocalIndex;
    }
  }
763
  return nParams();
764
765
}

766
/**
767
 * Returns the shrared pointer to the function conataining a parameter
768
 * @param ref :: The reference
769
770
 * @return A function containing parameter pointed to by ref
 */
771
IFunction_sptr CompositeFunction::getContainingFunction(const ParameterReference& ref)const
772
{
Peterson, Peter's avatar
Peterson, Peter committed
773
  for(size_t iFun=0;iFun<nFunctions();iFun++)
774
  {
775
776
    IFunction_sptr fun = getFunction(iFun);
    if (fun->getParameterIndex(ref) < fun->nParams())
777
    {
778
      return fun;
779
780
    }
  }
781
782
783
  return IFunction_sptr();
}

784
785
786
787
788
789
790
791
792
/**
 * Enable/disable numeric derivative calculation.
 * @param yes :: Set to true to use numeric derivative calculation.
 */
void CompositeFunction::useNumericDerivatives( bool yes ) const
{
  m_useNumericDerivatives = yes;
}

793
794
795
796
797
798
799
800
801
802
/// 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() );
  }
}
803

804
805
} // namespace API
} // namespace Mantid