CompositeFunction.cpp 25.1 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

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

namespace Mantid
{
namespace API
{

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

22
//DECLARE_FUNCTION(CompositeFunction)
23

24
25
/// Copy contructor
CompositeFunction::CompositeFunction(const CompositeFunction& f)
26
:m_nActive(f.m_nParams),m_nParams(f.m_nParams),m_iConstraintFunction(0)
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
  m_functions.assign(f.m_functions.begin(),f.m_functions.end());
  m_activeOffsets.assign(f.m_activeOffsets.begin(),f.m_activeOffsets.end());
  m_paramOffsets.assign(f.m_paramOffsets.begin(),f.m_paramOffsets.end());
}

///Assignment operator
CompositeFunction& CompositeFunction::operator=(const CompositeFunction& f)
{
  m_nActive = f.m_nActive;
  m_nParams = f.m_nParams;
  m_functions.assign(f.m_functions.begin(),f.m_functions.end());
  m_activeOffsets.assign(f.m_activeOffsets.begin(),f.m_activeOffsets.end());
  m_paramOffsets.assign(f.m_paramOffsets.begin(),f.m_paramOffsets.end());
41
  m_iConstraintFunction = f.m_iConstraintFunction;
42
43
44
45
46
47
  return *this;
}

///Destructor
CompositeFunction::~CompositeFunction()
{
Peterson, Peter's avatar
Peterson, Peter committed
48
  for(size_t i=0;i<nFunctions();i++)
49
50
51
52
53
54
55
56
57
    if (m_functions[i]) delete m_functions[i];
}


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

58
59
60
61
62
63
64
65
66
67
68
/** 
 * 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=(" << ... <<")";
 *   }
69
 * @return the string representation of the composite function
70
 */
71
72
73
std::string CompositeFunction::asString()const
{
  std::ostringstream ostr;
74
75
76
77
  if (name() != "CompositeFunctionMW")
  {
    ostr << "composite=" <<name() << ";";
  }
Peterson, Peter's avatar
Peterson, Peter committed
78
  for(size_t i=0;i<nFunctions();i++)
79
  {
80
    IFitFunction* fun = getFunction(i);
81
82
    bool isComp = dynamic_cast<CompositeFunction*>(fun) != 0;
    if (isComp) ostr << '(';
83
    ostr << fun->asString();
84
    if (isComp) ostr << ')';
85
86
87
88
89
90
    if (i < nFunctions() - 1)
    {
      ostr << ';';
    }
  }
  std::string ties;
91
  for(int i=0;i<nParams();i++)
92
93
94
95
  {
    const ParameterTie* tie = getTie(i);
    if (tie)
    {
96
      IFitFunction* fun = getFunction(functionIndex(i));
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
      std::string tmp = tie->asString(fun);
      if (tmp.empty())
      {
        tmp = tie->asString(this);
        if (!tmp.empty())
        {
          if (!ties.empty())
          {
            ties += ",";
          }
          ties += tmp;
        }
      }
    }
  }
  if (!ties.empty())
  {
    ostr << ";ties=(" << ties << ")";
115
116
117
118
  }
  return ostr.str();
}

119
/** Sets a new value to the i-th parameter.
120
121
122
 *  @param i :: The parameter index
 *  @param value :: The new value
 *  @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
123
 */
124
void CompositeFunction::setParameter(int i, const double& value, bool explicitlySet)
125
{
126
  int iFun = functionIndex(i);
127
  m_functions[ iFun ]->setParameter(i - m_paramOffsets[iFun],value,explicitlySet);
128
129
}

130
131
132
133
134
135
136
137
138
139
/** 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)
{
  int iFun = functionIndex(i);
  m_functions[ iFun ]->setParameterDescription(i - m_paramOffsets[iFun],description);
}

140
/** Get the i-th parameter.
141
 *  @param i :: The parameter index
142
 *  @return value of the requested parameter
143
 */
144
double CompositeFunction::getParameter(int i)const
145
{
Peterson, Peter's avatar
Peterson, Peter committed
146
  size_t iFun = functionIndex(i);
147
  return m_functions[ iFun ]->getParameter(i - m_paramOffsets[iFun]);
148
149
}

150
151
/**
 * Sets a new value to a parameter by name.
152
153
154
 * @param name :: The name of the parameter.
 * @param value :: The new value
 * @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
155
156
 */
void CompositeFunction::setParameter(const std::string& name, const double& value, bool explicitlySet)
157
{
158
  std::string pname;
159
  int index;
160
  parseName(name,index,pname);
161
162
163
164
165
166
  if (index < 0)
    throw std::invalid_argument("CompositeFunction::getParameter: parameter name must contain function index");
  else
  {   
    getFunction(index)->setParameter(pname,value,explicitlySet);
  }
167
168
}

169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/**
 * Sets a new description to a parameter by name.
 * @param name :: The name of the parameter.
 * @param value :: The new description
 */
void CompositeFunction::setParameterDescription(const std::string& name, const std::string& description)
{
  std::string pname;
  int index;
  parseName(name,index,pname);
  if (index < 0)
    throw std::invalid_argument("CompositeFunction::getParameter: parameter name must contain function index");
  else
  {   
    getFunction(index)->setParameterDescription(pname,description);
  }
}

187
188
/**
 * Parameters by name.
189
 * @param name :: The name of the parameter.
190
 * @return value of the requested named parameter
191
 */
192
193
double CompositeFunction::getParameter(const std::string& name)const
{
194
  std::string pname;
195
  int index;
196
  parseName(name,index,pname);
197
198
199
200
201
202
  if (index < 0)
    throw std::invalid_argument("CompositeFunction::getParameter: parameter name must contain function index");
  else
  {   
    return getFunction(index)->getParameter(pname);
  }
203
204
205
}

/// Total number of parameters
206
int CompositeFunction::nParams()const
207
208
209
210
{
  return m_nParams;
}

211
/**
212
 * 
213
 * @param name :: The name of a parameter
214
 * @return index of the requested named parameter
215
 */
216
int CompositeFunction::parameterIndex(const std::string& name)const
217
{
218
  std::string pname;
219
  int index;
220
  parseName(name,index,pname);
221
222
223
  if (index < 0)
    throw std::invalid_argument("CompositeFunction::getParameter: parameter name must contain function index");

224
  return getFunction(index)->parameterIndex(pname) + m_paramOffsets[index];
225
226
}

Nick Draper's avatar
re #100    
Nick Draper committed
227
/// Returns the name of parameter
228
/// @param i :: The index
Nick Draper's avatar
re #100    
Nick Draper committed
229
/// @return The name of the parameter
230
std::string CompositeFunction::parameterName(int i)const
231
{
232
  int iFun = functionIndex(i);
233
234
235
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
  return ostr.str();
236
237
}

238
239
240
241
242
243
244
245
246
247
248
/// Returns the description of parameter
/// @param i :: The index
/// @return The description of the parameter
std::string CompositeFunction::parameterDescription(size_t i)const
{
  int iFun = functionIndex(i);
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->parameterDescription(i - m_paramOffsets[iFun]);
  return ostr.str();
}

249
/// Number of active (in terms of fitting) parameters
250
int CompositeFunction::nActive()const
251
252
253
254
255
{
  return m_nActive;
}

/// Value of i-th active parameter. Override this method to make fitted parameters different from the declared
256
double CompositeFunction::activeParameter(int i)const
257
{
258
  int iFun = functionIndexActive(i);
259
260
261
262
263
264
  return m_functions[ iFun ]->activeParameter(i - m_activeOffsets[iFun]);
}

/// Set new value of i-th active parameter. Override this method to make fitted parameters different from the declared
void CompositeFunction::setActiveParameter(int i, double value)
{
265
  int iFun = functionIndexActive(i);
266
  m_functions[ iFun ]->setActiveParameter(i - m_activeOffsets[iFun],value);
267
268
269
270
271
272
273
274
275
}

/// Update parameters after a fitting iteration
void CompositeFunction::updateActive(const double* in)
{
  for(int iFun = 0; iFun < int(m_functions.size()); iFun++)
  {
    m_functions[ iFun ]->updateActive(in + m_activeOffsets[ iFun ]);
  }
276
  applyTies();
277
278
279
}

/// Returns "global" index of active parameter i
280
int CompositeFunction::indexOfActive(int i)const
281
{
282
  int iFun = functionIndexActive(i);
283
284
285
286
  return m_paramOffsets[ iFun ] + m_functions[ iFun ]->indexOfActive(i - m_activeOffsets[iFun]);
}

/// Returns the name of active parameter i
287
std::string CompositeFunction::nameOfActive(int i)const
288
{
289
  int iFun = functionIndexActive(i);
290
291
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->nameOfActive(i - m_activeOffsets[iFun]);
292
293
294
295
296
297
298
299
300
  return ostr.str();
}

/// Returns the description of active parameter i
std::string CompositeFunction::descriptionOfActive(size_t i)const
{
  int iFun = functionIndexActive(i);
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->descriptionOfActive(i - m_activeOffsets[iFun]);
301
  return ostr.str();
302
303
}

304
/**
305
 * query to see in the function is active
306
 * @param i :: The index of a declared parameter
307
 * @return true if parameter i is active
308
 */
309
bool CompositeFunction::isActive(int i)const
310
311
312
313
314
315
{
  int iFun = functionIndex(i);
  return m_functions[ iFun ]->isActive(i - m_paramOffsets[iFun]);
}

/**
316
 * @param i :: A declared parameter index to be removed from active
317
 */
318
void CompositeFunction::removeActive(int i)
319
{
320
  if (!isActive(i)) return;
321
322
  int iFun = functionIndex(i);
  int ia = m_activeOffsets[iFun] + m_functions[iFun]->activeIndex(i - m_paramOffsets[iFun]);
323
  m_IFitFunctionActive.erase(m_IFitFunctionActive.begin()+ia);
324
325
  m_functions[ iFun ]->removeActive(i - m_paramOffsets[iFun]);

326
  m_nActive--;
Peterson, Peter's avatar
Peterson, Peter committed
327
  for(size_t j=iFun+1;j<nFunctions();j++)
328
329
330
    m_activeOffsets[j] -= 1;
}

331
/** Makes a parameter active again. It doesn't change the parameter's tie.
332
 * @param i :: A declared parameter index to be restored to active
333
 */
334
void CompositeFunction::restoreActive(int i)
335
{
336
337
  int iFun = functionIndex(i);
  int ia = m_activeOffsets[iFun] + m_functions[iFun]->activeIndex(i - m_paramOffsets[iFun]);
338

339
  std::vector<int>::iterator itFun = 
340
    std::find_if(m_IFitFunctionActive.begin(),m_IFitFunctionActive.end(),std::bind2nd(std::greater<int>(),i));
341

342
  m_IFitFunctionActive.insert(itFun,1,ia);
343
344
345
  m_functions[ iFun ]->restoreActive(i - m_paramOffsets[iFun]);

  m_nActive++;
Peterson, Peter's avatar
Peterson, Peter committed
346
  for(size_t j=iFun+1;j<nFunctions();j++)
347
348
349
    m_activeOffsets[j] += 1;
}

350
/**
351
 * @param i :: The index of a declared parameter
352
353
354
 * @return The index of declared parameter i in the list of active parameters or -1
 *         if the parameter is tied.
 */
355
int CompositeFunction::activeIndex(int i)const
356
{
357
358
  int iFun = functionIndex(i);
  int j = m_functions[iFun]->activeIndex(i - m_paramOffsets[iFun]);
359
360
361
362
363
364
365

  if (j == -1) 
  {
    return -1;
  }

  return m_activeOffsets[iFun] + j;
366
367
}

368
369
370
371
372
373
374
375
/** Makes sure that the function is consistent. 
 */
void CompositeFunction::checkFunction()
{
  m_nParams = 0;
  m_nActive = 0;
  m_paramOffsets.clear();
  m_activeOffsets.clear();
376
377
  m_IFitFunction.clear();
  m_IFitFunctionActive.clear();
378

379
  std::vector<IFitFunction*> functions(m_functions.begin(),m_functions.end());
380
381
  m_functions.clear();

382
  for(std::vector<IFitFunction*>::size_type i=0;i<functions.size();i++)
383
  {
384
    IFitFunction* f = functions[i];
385
386
    CompositeFunction* cf = dynamic_cast<CompositeFunction*>(f);
    if (cf) cf->checkFunction();
387
388
389
390
    addFunction(f);
  }
}

391
/** Add a function
392
 * @param f :: A pointer to the added function
393
 * @return The function index
394
 */
395
int CompositeFunction::addFunction(IFitFunction* f)
396
{
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
397
398
  m_IFitFunction.insert(m_IFitFunction.end(),f->nParams(), static_cast<int>(m_functions.size()));
  m_IFitFunctionActive.insert(m_IFitFunctionActive.end(),f->nActive(),static_cast<int>(m_functions.size()));
399
400
401
402
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_activeOffsets.push_back(0);
    m_nParams = f->nParams();
    m_nActive = f->nActive();
  }
  else
  {
    m_paramOffsets.push_back(m_nParams);
    m_activeOffsets.push_back(m_nActive);
    m_nParams += f->nParams();
    m_nActive += f->nActive();
  }
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
415
  return static_cast<int>(m_functions.size())-1;
416
417
}

418
/** Remove a function
419
420
 * @param i :: The index of the function to remove
 * @param del :: The deletion flag. If true the function will be deleted otherwise - simply detached
421
 */
422
void CompositeFunction::removeFunction(int i, bool del)
423
{
Peterson, Peter's avatar
Peterson, Peter committed
424
  if ( i >= static_cast<int>(nFunctions()) )
425
426
    throw std::out_of_range("Function index out of range.");

427
  IFitFunction* fun = getFunction(i);
428

429
430
  int dna = fun->nActive();
  int dnp = fun->nParams();
431

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

  // Shift down the function indeces for parameters
446
  for(std::vector<int>::iterator it=m_IFitFunction.begin();it!=m_IFitFunction.end();)
447
  {
448

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

  // Shift down the function indeces for active parameters
464
  for(std::vector<int>::iterator it=m_IFitFunctionActive.begin();it!=m_IFitFunctionActive.end();)
465
466
467
  {
    if (*it == i)
    {
468
      it = m_IFitFunctionActive.erase(it);
469
    }
470
    else
471
    {
472
473
474
475
476
      if (*it > i)
      {
        *it -= 1;
      }
      it++;
477
478
479
480
481
    }
  }

  m_nActive -= dna;
  // Shift the active offsets down by the number of i-th function's active params
Peterson, Peter's avatar
Peterson, Peter committed
482
  for(size_t j=static_cast<size_t>(i+1);j<nFunctions();j++)
483
484
485
486
487
488
489
  {
    m_activeOffsets[j] -= dna;
  }
  m_activeOffsets.erase(m_activeOffsets.begin()+i);

  m_nParams -= dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
Peterson, Peter's avatar
Peterson, Peter committed
490
  for(size_t j=static_cast<size_t>(i+1);j<nFunctions();j++)
491
492
493
494
495
496
  {
    m_paramOffsets[j] -= dnp;
  }
  m_paramOffsets.erase(m_paramOffsets.begin()+i);

  m_functions.erase(m_functions.begin()+i);
497
498
499
500
  if (del)
  {
    delete fun;
  }
501
502
}

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

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

527
  IFitFunction* fun = getFunction(i);
528
529
  int na_old = fun->nActive();
  int np_old = fun->nParams();
530

531
532
  int na_new = f->nActive();
  int np_new = f->nParams();
533
534
535

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

  // Modify function indeces: The new function may have different number of active parameters
  {
557
    std::vector<int>::iterator itFun = std::find(m_IFitFunctionActive.begin(),m_IFitFunctionActive.end(),i);
558
    if (itFun != m_IFitFunctionActive.end())
559
560
561
    {
      if (na_old > na_new)
      {
562
        m_IFitFunctionActive.erase(itFun,itFun + na_old - na_new);
563
564
565
      }
      else if (na_old < na_new) 
      {
566
        m_IFitFunctionActive.insert(itFun,na_new - na_old,i);
567
568
569
570
      }
    }
    else if (na_new > 0)
    {
571
572
      itFun = std::find_if(m_IFitFunctionActive.begin(),m_IFitFunctionActive.end(),std::bind2nd(std::greater<int>(),i));
      m_IFitFunctionActive.insert(itFun,na_new,i);
573
574
575
    }
  }

576
  int dna = na_new - na_old;
577
578
  m_nActive += dna;
  // Recalc the active offsets 
Peterson, Peter's avatar
Peterson, Peter committed
579
  for(size_t j=static_cast<size_t>(i+1);j<nFunctions();j++)
580
581
582
583
  {
    m_activeOffsets[j] += dna;
  }

584
  int dnp = np_new - np_old;
585
586
  m_nParams += dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
Peterson, Peter's avatar
Peterson, Peter committed
587
  for(size_t j=static_cast<size_t>(i+1);j<nFunctions();j++)
588
589
590
591
592
593
594
595
  {
    m_paramOffsets[j] += dnp;
  }

  m_functions[i] = f;
  delete fun;
}

596
/**
597
 * @param i :: The index of the function
598
 * @return function at the requested index
599
 */
Peterson, Peter's avatar
Peterson, Peter committed
600
IFitFunction* CompositeFunction::getFunction(size_t i)const
601
{
Peterson, Peter's avatar
Peterson, Peter committed
602
  if ( i >= nFunctions() )
603
  {
604
    throw std::out_of_range("Function index out of range.");
605
  }
606
607
608
  return m_functions[i];
}

609
610
/**
 * Get the index of the function to which parameter i belongs
611
 * @param i :: The parameter index
612
 * @return function index of the requested parameter
613
 */
Peterson, Peter's avatar
Peterson, Peter committed
614
size_t CompositeFunction::functionIndex(size_t i)const
615
{
616
617
618
619
620
  // Casting this to an int could result in it being turned into a -1
  // so need to check that also. 
  // @todo: nParams should return size_t and get rid of -1 error returns
  int iindex = static_cast<int>(i);
  if( iindex >= nParams() || iindex < 0 )
621
  {
622
    throw std::out_of_range("Function parameter index out of range.");
623
  }
624
  return m_IFitFunction[i];
625
626
627
628
}

/**
 * Get the index of the function to which parameter i belongs
629
 * @param i :: The active parameter index
630
 * @return active function index of the requested parameter
631
 */
Peterson, Peter's avatar
Peterson, Peter committed
632
size_t CompositeFunction::functionIndexActive(size_t i)const
633
{
634
635
636
637
638
  // Casting this to an int could result in it being turned into a -1
  // so need to check that also. 
  // @todo: nParams should return size_t and get rid of -1 error returns
  int iindex = static_cast<int>(i);
  if( iindex >= nParams() || iindex < 0 )
639
    throw std::out_of_range("Function parameter index out of range.");
640
  return m_IFitFunctionActive[i];
641
642
643
}

/**
644
645
646
* @param varName :: The variable name which may contain function index ( [f<index.>]name )
* @param index :: Receives function index or -1 
* @param name :: Receives the parameter name
647
*/
648
void CompositeFunction::parseName(const std::string& varName,int& index, std::string& name)
649
{
650
651
652
653
  size_t i = varName.find('.');
  if (i == std::string::npos)
  {
    name = varName;
654
655
    index = -1;
    return;
656
657
658
659
660
661
662
663
664
665
666
667
668
669
  }
  else
  {
    if (varName[0] != 'f')
      throw std::invalid_argument("External function parameter name must start with 'f'");

    std::string sindex = varName.substr(1,i-1);
    index = boost::lexical_cast<int>(sindex);

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

    name = varName.substr(i+1);
  }
670
671
}

672
/** Returns the index of parameter i as it declared in its function
673
 * @param i :: The parameter index
674
675
 * @return The local index of the parameter
 */
676
int CompositeFunction::parameterLocalIndex(int i)const
677
678
679
680
681
{
  int iFun = functionIndex(i);
  return i - m_paramOffsets[iFun];
}

682
/** Returns the name of parameter i as it declared in its function
683
 * @param i :: The parameter index
684
685
 * @return The pure parameter name (without the function identifier f#.)
 */
686
std::string CompositeFunction::parameterLocalName(int i)const
687
688
689
690
691
{
  int iFun = functionIndex(i);
  return m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
}

Janik Zikovsky's avatar
Janik Zikovsky committed
692
693
694
695
696
697
// /** Initialize the function providing it the workspace
// * @param workspace :: The shared pointer to a workspace to which the function will be fitted
// * @param spec :: The number of a spectrum for fitting
// * @param xMin :: The minimum bin index of spectrum spec that will be used in fitting
// * @param xMax :: The maximum bin index of spectrum spec that will be used in fitting
// */
698
699
700
701
702
703
704
705
//void CompositeFunction::setMatrixWorkspace(boost::shared_ptr<const API::MatrixWorkspace> workspace,int spec,int xMin,int xMax)
//{
//  IFitFunction::setMatrixWorkspace(workspace,spec,xMin,xMax);
//  for(int i=0;i<nFunctions();i++)
//  {
//    getFunction(i)->setMatrixWorkspace(workspace,spec,xMin,xMax);
//  }
//}
706

707
/**
708
 * Apply the ties.
709
710
711
 */
void CompositeFunction::applyTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
712
  for(size_t i=0;i<nFunctions();i++)
713
714
715
716
717
718
719
720
721
722
  {
    getFunction(i)->applyTies();
  }
}

/**
 * Clear the ties. 
 */
void CompositeFunction::clearTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
723
  for(size_t i=0;i<nFunctions();i++)
724
725
726
727
728
729
  {
    getFunction(i)->clearTies();
  }
}

/** Removes i-th parameter's tie if it is tied or does nothing.
730
 * @param i :: The index of the tied parameter.
731
732
 * @return True if successfull
 */
733
bool CompositeFunction::removeTie(int i)
734
{
735
  int iFun = functionIndex(i);
736
737
738
739
740
741
742
743
744
  bool res = m_functions[ iFun ]->removeTie(i - m_paramOffsets[iFun]);
  if (res)
  {
    m_nActive++;
  }
  return res;
}

/** Get the tie of i-th parameter
745
 * @param i :: The parameter index
746
 * @return A pointer to the tie.
747
 */
748
ParameterTie* CompositeFunction::getTie(int i)const
749
750
751
752
753
754
755
{
  int iFun = functionIndex(i);
  return m_functions[ iFun ]->getTie(i - m_paramOffsets[iFun]);
}

/**
 * Attaches a tie to this function. The attached tie is owned by the function.
756
 * @param tie :: A pointer to a new tie
757
758
759
 */
void CompositeFunction::addTie(ParameterTie* tie)
{
760
  int i = getParameterIndex(*tie);
761
762
763
764
765
766
767
768
769
770
  if (i < 0)
  {
    throw std::logic_error("Trying to use a tie on a parameter not belonging to this function");
  }
  int iFun = functionIndex(i);
  m_functions[iFun]->addTie(tie);
}

/**
 * Declare a new parameter. To used in the implementation'c constructor.
771
772
 * @param name :: The parameter name.
 * @param initValue :: The initial value for the parameter
773
 */
774
void CompositeFunction::declareParameter(const std::string& name, double initValue, const std::string& description)
775
{
776
777
  (void) name; //Avoid compiler warning
  (void) initValue; //Avoid compiler warning
778
  (void) description; //Avoid compiler warning
779
780
781
782
  throw Kernel::Exception::NotImplementedError("CompositeFunction cannot not have its own parameters.");
}

/** Add a constraint
783
 *  @param ic :: Pointer to a constraint.
784
785
786
 */
void CompositeFunction::addConstraint(IConstraint* ic)
{
787
788
789
  int i = getParameterIndex(*ic);
  int iFun = functionIndex(i);
  getFunction(iFun)->addConstraint(ic);
790
791
}

792
793
void CompositeFunction::setParametersToSatisfyConstraints()
{
Peterson, Peter's avatar
Peterson, Peter committed
794
  for(size_t i=0;i<nFunctions();i++)
795
796
797
798
799
  {
    getFunction(i)->setParametersToSatisfyConstraints();
  }
}

Nick Draper's avatar
re #100    
Nick Draper committed
800
/// Get constraint
801
/// @param i :: the index
Nick Draper's avatar
re #100    
Nick Draper committed
802
/// @return A pointer to the constraint
803
IConstraint* CompositeFunction::getConstraint(int i)const
804
{
805
  int iFun = functionIndex(i);
806
  return m_functions[ iFun ]->getConstraint(i - m_paramOffsets[iFun]);
807
808
}

809
/** Remove a constraint
810
 * @param parName :: The name of a parameter which constarint to remove.
811
812
813
814
815
816
817
818
 */
void CompositeFunction::removeConstraint(const std::string& parName)
{
  int iPar = parameterIndex(parName);
  int iFun = functionIndex(iPar);
  getFunction(iFun)->removeConstraint(parameterLocalName(iPar));
}

819
/** Checks if a constraint has been explicitly set
820
 *  @param i :: The parameter index
821
 *  @return true if the function is explicitly set
822
 */
823
bool CompositeFunction::isExplicitlySet(int i)const
824
{
825
  int iFun = functionIndex(i);
826
827
828
  return m_functions[ iFun ]->isExplicitlySet(i - m_paramOffsets[iFun]);
}

829
830
/**
 * Returns the index of parameter if the ref points to one of the member function or -1
831
 * @param ref :: A reference to a parameter
832
833
 * @return Parameter index or -1
 */
834
int CompositeFunction::getParameterIndex(const ParameterReference& ref)const
835
{
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
836
  if (ref.getFunction() == this && static_cast<int>(ref.getIndex()) < nParams())
837
  {
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
838
    return static_cast<int>(ref.getIndex());
839
  }
Peterson, Peter's avatar
Peterson, Peter committed
840
  for(size_t iFun=0;iFun<nFunctions();iFun++)
841
  {
842
    int iLocalIndex = getFunction(iFun)->getParameterIndex(ref);
843
844
845
846
847
    if (iLocalIndex >= 0)
    {
      return m_paramOffsets[iFun] + iLocalIndex;
    }
  }
848
849
850
  return -1;
}

851
/**
852
 * @param ref :: The reference
853
854
 * @return A function containing parameter pointed to by ref
 */
855
IFitFunction* CompositeFunction::getContainingFunction(const ParameterReference& ref)const
856
{
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
857
  if (ref.getFunction() == this && static_cast<int>(ref.getIndex()) < nParams())
858
859
860
  {
    return ref.getFunction();
  }
Peterson, Peter's avatar
Peterson, Peter committed
861
  for(size_t iFun=0;iFun<nFunctions();iFun++)
862
  {
863
    IFitFunction* fun = static_cast<IFitFunction*>(getFunction(iFun)->getContainingFunction(ref));
864
865
866
867
868
869
870
    if (fun)
    {
      return getFunction(iFun);
    }
  }
  return NULL;
}
871

872
/**
873
 * @param fun :: The searched function
874
875
 * @return A function containing the argument function fun
 */
876
IFitFunction* CompositeFunction::getContainingFunction(const IFitFunction* fun)
877
878
879
880
881
{
  if (fun == this)
  {
    return this;
  }
Peterson, Peter's avatar
Peterson, Peter committed
882
  for(size_t iFun=0;iFun<nFunctions();iFun++)
883
  {
884
    IFitFunction* f = static_cast<IFitFunction*>(getFunction(iFun)->getContainingFunction(fun));
885
886
887
888
889
890
891
892
    if (f)
    {
      return getFunction(iFun);
    }
  }
  return NULL;
}

893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
//void CompositeFunction::setWorkspace(boost::shared_ptr<Workspace> ws,const std::string& slicing)
//{
//  IFitFunction::setWorkspace(ws,slicing);
//  for(int iFun=0;iFun<nFunctions();iFun++)
//  {
//    getFunction(iFun)->setUpNewStuff(m_xValues,m_weights);
//  }
//}

//void CompositeFunction::setUpNewStuff(boost::shared_array<double> xs,boost::shared_array<double> weights)
//{
//  IFitFunction::setUpNewStuff(xs,weights);
//  for(int iFun=0;iFun<nFunctions();iFun++)
//  {
//    getFunction(iFun)->setUpNewStuff(xs,weights);
//  }
//}
910

911
912
} // namespace API
} // namespace Mantid