Skip to content

Commit d5ca14e

Browse files
committedNov 1, 2022
Enable automatic re-generation of HKL's for a PowderPatternDiffraction when the spacegroup is changed, or when the lattice parameters change (the latter only outside of an optimisation). This is done by making all the HKL attributes mutable, and overloading the SetHKL and GenHKLFullSpace, GenHKLFullSpace2 with a protected const version, which should only be used for powder diffraction (and not single crystal data).
This should address diffpy/pyobjcryst#32 Removed mCorrTextureEllipsoid.InitRefParList() from PowderPatternDiffraction::GenHKLFullSpace since the parameter initialisation is already done in the TextureEllipsoid constructor.
1 parent 3069c35 commit d5ca14e

File tree

4 files changed

+140
-31
lines changed

4 files changed

+140
-31
lines changed
 

‎ObjCryst/ObjCryst/PowderPattern.cpp

+45-16
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ PowderPatternDiffraction::PowderPatternDiffraction():
794794
mpReflectionProfile(0),
795795
mCorrLorentz(*this),mCorrPolar(*this),mCorrSlitAperture(*this),
796796
mCorrTextureMarchDollase(*this),mCorrTextureEllipsoid(*this),mCorrTOF(*this),mCorrCylAbs(*this),mExtractionMode(false),
797-
mpLeBailData(0),mFrozenLatticePar(6),mFreezeLatticePar(false),mFrozenBMatrix(3,3)
797+
mpLeBailData(0),mFrozenLatticePar(6),mFreezeLatticePar(false),mFrozenBMatrix(3,3),mGenHKLBMatrix(3,3)
798798
{
799799
VFN_DEBUG_MESSAGE("PowderPatternDiffraction::PowderPatternDiffraction()",10)
800800
mIsScalable=true;
@@ -808,13 +808,14 @@ mpLeBailData(0),mFrozenLatticePar(6),mFreezeLatticePar(false),mFrozenBMatrix(3,3
808808
mClockMaster.AddChild(mpReflectionProfile->GetClockMaster());
809809
for(unsigned int i=0;i<3;++i) mFrozenLatticePar(i)=5;
810810
for(unsigned int i=3;i<6;++i) mFrozenLatticePar(i)=M_PI/2;
811+
mGenHKLBMatrix=0;
811812
}
812813

813814
PowderPatternDiffraction::PowderPatternDiffraction(const PowderPatternDiffraction &old):
814815
mpReflectionProfile(0),
815816
mCorrLorentz(*this),mCorrPolar(*this),mCorrSlitAperture(*this),
816817
mCorrTextureMarchDollase(*this),mCorrTextureEllipsoid(*this),mCorrTOF(*this),mCorrCylAbs(*this),mExtractionMode(false),
817-
mpLeBailData(0),mFrozenLatticePar(6),mFreezeLatticePar(old.FreezeLatticePar()),mFrozenBMatrix(3,3)
818+
mpLeBailData(0),mFrozenLatticePar(6),mFreezeLatticePar(old.FreezeLatticePar()),mFrozenBMatrix(3,3),mGenHKLBMatrix(3,3)
818819
{
819820
this->AddSubRefObj(mCorrTextureMarchDollase);
820821
this->AddSubRefObj(mCorrTextureEllipsoid);
@@ -831,7 +832,7 @@ mpLeBailData(0),mFrozenLatticePar(6),mFreezeLatticePar(old.FreezeLatticePar()),m
831832
mClockMaster.AddChild(mClockLorentzPolarSlitCorrPar);
832833
mClockMaster.AddChild(mpReflectionProfile->GetClockMaster());
833834
for(unsigned int i=0;i<6;++i) mFrozenLatticePar(i)=old.GetFrozenLatticePar(i);
834-
mFrozenBMatrix=old.GetBMatrix();
835+
mGenHKLBMatrix=0;
835836
}
836837

837838
PowderPatternDiffraction::~PowderPatternDiffraction()
@@ -913,29 +914,31 @@ ReflectionProfile& PowderPatternDiffraction::GetProfile()
913914

914915
// Disable the base-class function.
915916
void PowderPatternDiffraction::GenHKLFullSpace(
916-
const REAL maxTheta, const bool useMultiplicity)
917+
const REAL maxTheta, const bool useMultiplicity) const
917918
{
918919
// This should be never called.
919920
abort();
920921
}
921922

922-
void PowderPatternDiffraction::GenHKLFullSpace()
923+
void PowderPatternDiffraction::GenHKLFullSpace()const
923924
{
924925
VFN_DEBUG_ENTRY("PowderPatternDiffraction::GenHKLFullSpace():",5)
925926
float stol;
926927
if(this->GetRadiation().GetWavelengthType()==WAVELENGTH_TOF)
927928
stol=mpParentPowderPattern->X2STOL(mpParentPowderPattern->GetPowderPatternXMin());
928929
else
929930
stol=mpParentPowderPattern->X2STOL(mpParentPowderPattern->GetPowderPatternXMax());
930-
if(stol>1) stol=1; // Do not go beyond 0.5 A resolution (mostly for TOF data)
931+
if(stol>2) stol=2; // Do not go beyond 0.25 A resolution (mostly for TOF data)
931932
this->ScatteringData::GenHKLFullSpace2(stol,true);
932933
if((mExtractionMode) && (mFhklObsSq.numElements()!=this->GetNbRefl()))
933934
{// Reflections changed, so ScatteringData::PrepareHKLarrays() probably reseted mFhklObsSq
934-
VFN_DEBUG_ENTRY("PowderPatternDiffraction::GenHKLFullSpace(): need to reset observed intensities",7)
935-
mFhklObsSq.resize(this->GetNbRefl());
936-
mFhklObsSq=100;
935+
VFN_DEBUG_ENTRY("PowderPatternDiffraction::GenHKLFullSpace(): need to resize observed intensities",7)
936+
const int n0 = mFhklObsSq.numElements();
937+
mFhklObsSq.resizeAndPreserve(this->GetNbRefl());
938+
for(int i=n0;i<this->GetNbRefl();i++) mFhklObsSq(i)=100;
937939
}
938-
mCorrTextureEllipsoid.InitRefParList();// #TODO: SHould this be here ?
940+
// Save the used Bmatrix
941+
mGenHKLBMatrix = this->GetBMatrix();
939942
VFN_DEBUG_EXIT("PowderPatternDiffraction::GenHKLFullSpace():"<<this->GetNbRefl(),5)
940943
}
941944
void PowderPatternDiffraction::BeginOptimization(const bool allowApproximations,
@@ -1319,12 +1322,38 @@ void PowderPatternDiffraction::CalcPowderPattern() const
13191322

13201323
VFN_DEBUG_ENTRY("PowderPatternDiffraction::CalcPowderPattern():",3)
13211324

1322-
// :TODO: Can't do this as this is non-const
1323-
//if(this->GetCrystal().GetSpaceGroup().GetClockSpaceGroup()>mClockHKL)
1324-
// this->GenHKLFullSpace();
1325-
//
1326-
// The workaround is to call Prepare() (non-const) before every calculation
1327-
// when a modifictaion may have occured.
1325+
if(this->GetCrystal().GetSpaceGroup().GetClockSpaceGroup()>mClockHKL)
1326+
{
1327+
VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcPowderPattern():"
1328+
"spacegroup has changed, re-generating HKL's",5)
1329+
cout<<"PowderPatternDiffraction::CalcPowderPattern(): spacegroup has changed, re-generating HKL's"<<endl;
1330+
this->GenHKLFullSpace();
1331+
}
1332+
else if((!this->IsBeingRefined()) && (this->GetCrystal().GetClockLatticePar()>mClockHKL))
1333+
{
1334+
// Check if the B matrix changed significantly and requires regenerating the HKL's
1335+
// This is never done during optimisation
1336+
1337+
//mBMatrix = aa , bb*cos(gammaa) , cc*cos(betaa) ,
1338+
// 0 , bb*sin(gammaa) ,-cc*sin(betaa)*cos(alpha),
1339+
// 0 , 0 ,1/c;
1340+
bool needgen=false;
1341+
const REAL r = 0.005; // Tolerate 0.5% difference
1342+
if(abs(this->GetBMatrix()(0)-mGenHKLBMatrix(0))>(r*this->GetBMatrix()(0))) needgen=true;
1343+
else if(abs(this->GetBMatrix()(4)-mGenHKLBMatrix(4))>(r*this->GetBMatrix()(4))) needgen=true;
1344+
else if(abs(this->GetBMatrix()(1)-mGenHKLBMatrix(1))>(r*this->GetBMatrix()(4))) needgen=true;
1345+
else if(abs(this->GetBMatrix()(8)-mGenHKLBMatrix(8))>(r*this->GetBMatrix()(8))) needgen=true;
1346+
else if(abs(this->GetBMatrix()(2)-mGenHKLBMatrix(2))>(r*this->GetBMatrix()(8))) needgen=true;
1347+
else if(abs(this->GetBMatrix()(5)-mGenHKLBMatrix(5))>(r*this->GetBMatrix()(8))) needgen=true;
1348+
if(needgen)
1349+
{
1350+
VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcPowderPattern():"
1351+
"lattice parameters have changed by more than 0.5%, re-generating HKL's",5)
1352+
cout<<"PowderPatternDiffraction::CalcPowderPattern():"
1353+
"lattice parameters have changed by more than 0.5%, re-generating HKL's"<<endl;
1354+
this->GenHKLFullSpace();
1355+
}
1356+
}
13281357

13291358
this->CalcIhkl();
13301359
this->CalcPowderReflProfile();

‎ObjCryst/ObjCryst/PowderPattern.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ class PowderPatternDiffraction : virtual public PowderPatternComponent,public Sc
365365
const ReflectionProfile& GetProfile()const;
366366
/// Get reflection profile
367367
ReflectionProfile& GetProfile();
368-
virtual void GenHKLFullSpace();
368+
virtual void GenHKLFullSpace()const;
369369
virtual void XMLOutput(ostream &os,int indent=0)const;
370370
virtual void XMLInput(istream &is,const XMLCrystTag &tag);
371371
//virtual void XMLInputOld(istream &is,const IOCrystTag &tag);
@@ -556,14 +556,16 @@ class PowderPatternDiffraction : virtual public PowderPatternComponent,public Sc
556556
bool mFreezeLatticePar;
557557
/// Local B Matrix, used if mFreezeLatticePar is true
558558
mutable CrystMatrix_REAL mFrozenBMatrix;
559-
#ifdef __WX__CRYST__
559+
/// Bmatrix the last time the HKL parameters were generated
560+
mutable CrystMatrix_REAL mGenHKLBMatrix;
561+
#ifdef __WX__CRYST__
560562
public:
561563
virtual WXCrystObjBasic* WXCreate(wxWindow*);
562564
friend class WXPowderPatternDiffraction;
563565
#endif
564566
private:
565567
// Avoid compiler warnings. Explicitly hide the base-class method.
566-
void GenHKLFullSpace(const REAL, const bool);
568+
void GenHKLFullSpace(const REAL, const bool) const;
567569
};
568570

569571
//######################################################################

‎ObjCryst/ObjCryst/ScatteringData.cpp

+21-2
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,13 @@ ScatteringData::~ScatteringData()
513513
void ScatteringData::SetHKL(const CrystVector_REAL &h,
514514
const CrystVector_REAL &k,
515515
const CrystVector_REAL &l)
516+
{
517+
const_cast<const ScatteringData*>(this)->ScatteringData::SetHKL(h,k,l);
518+
}
519+
520+
void ScatteringData::SetHKL(const CrystVector_REAL &h,
521+
const CrystVector_REAL &k,
522+
const CrystVector_REAL &l) const
516523
{
517524
VFN_DEBUG_ENTRY("ScatteringData::SetHKL(h,k,l)",5)
518525
mNbRefl=h.numElements();
@@ -525,6 +532,11 @@ void ScatteringData::SetHKL(const CrystVector_REAL &h,
525532
}
526533

527534
void ScatteringData::GenHKLFullSpace2(const REAL maxSTOL,const bool unique)
535+
{
536+
const_cast<const ScatteringData*>(this)->ScatteringData::GenHKLFullSpace2(maxSTOL, unique);
537+
}
538+
539+
void ScatteringData::GenHKLFullSpace2(const REAL maxSTOL,const bool unique) const
528540
{
529541
//(*fpObjCrystInformUser)("Generating Full HKL list...");
530542
VFN_DEBUG_ENTRY("ScatteringData::GenHKLFullSpace2()",5)
@@ -621,6 +633,11 @@ void ScatteringData::GenHKLFullSpace2(const REAL maxSTOL,const bool unique)
621633
}
622634

623635
void ScatteringData::GenHKLFullSpace(const REAL maxTheta,const bool useMultiplicity)
636+
{
637+
const_cast<const ScatteringData*>(this)->ScatteringData::GenHKLFullSpace(maxTheta, useMultiplicity);
638+
}
639+
640+
void ScatteringData::GenHKLFullSpace(const REAL maxTheta,const bool useMultiplicity) const
624641
{
625642
VFN_DEBUG_ENTRY("ScatteringData::GenHKLFullSpace()",5)
626643
if(this->GetRadiation().GetWavelength()(0) <=.01)
@@ -642,6 +659,7 @@ void ScatteringData::SetCrystal(Crystal &crystal)
642659
this->AddSubRefObj(crystal);
643660
crystal.RegisterClient(*this);
644661
mClockMaster.AddChild(mpCrystal->GetClockLatticePar());
662+
mClockMaster.AddChild(mpCrystal->GetSpaceGroup().GetClockSpaceGroup());
645663
mClockGeomStructFact.Reset();
646664
mClockStructFactor.Reset();
647665
}
@@ -914,7 +932,7 @@ void ScatteringData::SetApproximationFlag(const bool allow)
914932
this->RefinableObj::SetApproximationFlag(allow);
915933
}
916934

917-
void ScatteringData::PrepareHKLarrays()
935+
void ScatteringData::PrepareHKLarrays() const
918936
{
919937
VFN_DEBUG_ENTRY("ScatteringData::PrepareHKLarrays()"<<mNbRefl<<" reflections",5)
920938
mFhklCalcReal.resize(mNbRefl);
@@ -996,7 +1014,7 @@ long ScatteringData::GetNbReflBelowMaxSinThetaOvLambda()const
9961014
const RefinableObjClock& ScatteringData::GetClockNbReflBelowMaxSinThetaOvLambda()const
9971015
{return mClockNbReflUsed;}
9981016

999-
CrystVector_long ScatteringData::SortReflectionBySinThetaOverLambda(const REAL maxSTOL)
1017+
CrystVector_long ScatteringData::SortReflectionBySinThetaOverLambda(const REAL maxSTOL) const
10001018
{
10011019
TAU_PROFILE("ScatteringData::SortReflectionBySinThetaOverLambda()","void ()",TAU_DEFAULT);
10021020
VFN_DEBUG_ENTRY("ScatteringData::SortReflectionBySinThetaOverLambda()",5)
@@ -1636,6 +1654,7 @@ void ScatteringData::CalcGeomStructFactor() const
16361654
if( (mClockGeomStructFact>mpCrystal->GetClockScattCompList())
16371655
&&(mClockGeomStructFact>mClockHKL)
16381656
&&(mClockGeomStructFact>mClockNbReflUsed)
1657+
&&(mClockGeomStructFact>mpCrystal->GetSpaceGroup().GetClockSpaceGroup())
16391658
&&(mClockGeomStructFact>mpCrystal->GetMasterClockScatteringPower())) return;
16401659
TAU_PROFILE("ScatteringData::GeomStructFactor()","void (Vx,Vy,Vz,data,M,M,bool)",TAU_DEFAULT);
16411660
VFN_DEBUG_ENTRY("ScatteringData::GeomStructFactor(Vx,Vy,Vz,...)",3)

‎ObjCryst/ObjCryst/ScatteringData.h

+69-10
Original file line numberDiff line numberDiff line change
@@ -292,14 +292,28 @@ class Radiation: public RefinableObj
292292
* This class only computes structure factor, but no intensity. i.e. it does
293293
* not include any correction such as absorption, Lorentz or Polarization.
294294
*
295-
* Does this really need to be a RefinableObj ?
296295
* \todo Optimize computation for Bijvoet/Friedel mates. To do this, generate
297296
* an internal list of 'true independent reflections', with two entries for each,
298297
* for both mates, and make the 'real' reflections only a reference to these reflections.
299298
*
300299
* \todo a \b lot of cleaning is necessary in the computing of structure
301300
* factors, for (1) the 'preparation' part (deciding what needs to be recomputed)
302301
* and (2) to allow anisotropic temperature factors (or other anisotropic parts)
302+
*
303+
* \note
304+
* all H,K,L related parameters are mutable so that a PowderPatternDiffraction
305+
* list of reflections can be updated whenever the spacegroup or
306+
* lattice parameters are changed, and this needs to automatically happen
307+
* even when calling const-functions like PowderPatternDiffraction::CalcPowderPattern().
308+
*
309+
* \par
310+
* Nevertheless this 'const' modification of HKL's are meant to be purely internal,
311+
* so the const functions are all protected, and the non-const ones (such as
312+
* SetHKL or GenHKLFullSpace) are public.
313+
*
314+
* \par
315+
* Single crystal classes should not make use of the new const functions since
316+
* changing the list of HKL's is effectively mutating the object.
303317
*/
304318
//######################################################################
305319
class ScatteringData: virtual public RefinableObj
@@ -463,13 +477,58 @@ class ScatteringData: virtual public RefinableObj
463477
/// Clock the last time the number of reflections used was changed
464478
const RefinableObjClock& GetClockNbReflBelowMaxSinThetaOvLambda()const;
465479
protected:
480+
/** \brief \internal input H,K,L
481+
*
482+
* \param h,k,l: REAL arrays (vectors with NbRefl elements -same size),
483+
*with the h, k and l coordinates of all reflections.
484+
*/
485+
virtual void SetHKL( const CrystVector_REAL &h,
486+
const CrystVector_REAL &k,
487+
const CrystVector_REAL &l) const;
488+
/** \brief Generate a list of h,k,l to describe a full reciprocal space,
489+
* up to a given maximum theta value
490+
*
491+
* \param maxTheta:maximum theta value
492+
* \param unique: if set to true, only unique reflections will be listed.
493+
* Bijvoet (Friedel) pairs
494+
* are NOT merged, for 'anomalous' reasons, unless you have chosen to ignore the
495+
* imaginary part of the scattering factor.
496+
*
497+
* The multiplicity is always stored in ScatteringData::mMultiplicity.
498+
*
499+
* \warning The ScatteringData object must already have been assigned
500+
* a crystal object using SetCrystal(), and the experimental wavelength
501+
* must also have been set before calling this function.
502+
*/
503+
virtual void GenHKLFullSpace2(const REAL maxsithsl,
504+
const bool unique=false) const;
505+
/** \brief \internal Generate a list of h,k,l to describe a full reciprocal space,
506+
* up to a given maximum theta value
507+
*
508+
* \param maxsithsl:maximum sin(theta)/lambda=1/2d value
509+
* \param unique: if set to true, only unique reflections will be listed.
510+
* Bijvoet (Friedel) pairs
511+
* are NOT merged, for 'anomalous' reasons, unless you have chosen to ignore the
512+
* imaginary part of the scattering factor.
513+
*
514+
* The multiplicity is always stored in ScatteringData::mMultiplicity.
515+
*
516+
* \warning The ScatteringData object must already have been assigned
517+
* a crystal object using SetCrystal(), and the experimental wavelength
518+
* must also have been set before calling this function.
519+
*
520+
* \deprecated Rather use PowderPattern::GenHKLFullSpace2,
521+
* with a maximum sin(theta)/lambda value, which also works for dispersive experiments.
522+
*/
523+
virtual void GenHKLFullSpace(const REAL maxTheta,
524+
const bool unique=false) const;
466525
/// \internal This function is called after H,K and L arrays have
467526
/// been initialized or modified.
468-
virtual void PrepareHKLarrays() ;
527+
virtual void PrepareHKLarrays() const;
469528
/// \internal sort reflections by theta values (also get rid of [0,0,0] if present)
470529
/// If maxSTOL >0, then only reflections where sin(theta)/lambda<maxSTOL are kept
471530
/// \return an array with the subscript of the kept reflections (for inherited classes)
472-
virtual CrystVector_long SortReflectionBySinThetaOverLambda(const REAL maxSTOL=-1.);
531+
virtual CrystVector_long SortReflectionBySinThetaOverLambda(const REAL maxSTOL=-1.) const;
473532
/// \internal Get rid of extinct reflections. Useful after GenHKLFullSpace().
474533
/// Do not use this if you have a list of observed reflections !
475534
///
@@ -532,9 +591,9 @@ class ScatteringData: virtual public RefinableObj
532591
void CalcStructFactVariance()const;
533592

534593
/// Number of H,K,L reflections
535-
long mNbRefl;
594+
mutable long mNbRefl;
536595
/// H,K,L coordinates
537-
CrystVector_REAL mH, mK, mL ;
596+
mutable CrystVector_REAL mH, mK, mL ;
538597
/// H,K,L integer coordinates
539598
mutable CrystVector_long mIntH, mIntK, mIntL ;
540599
/// H,K,L coordinates, multiplied by 2PI
@@ -543,13 +602,13 @@ class ScatteringData: virtual public RefinableObj
543602
mutable CrystVector_REAL mX, mY, mZ ;
544603

545604
///Multiplicity for each reflections (mostly for powder diffraction)
546-
CrystVector_int mMultiplicity ;
605+
mutable CrystVector_int mMultiplicity ;
547606

548607
/** Expected intensity factor for all reflections.
549608
*
550609
* See SpaceGroup::GetExpectedIntensityFactor()
551610
*/
552-
CrystVector_int mExpectedIntensityFactor;
611+
mutable CrystVector_int mExpectedIntensityFactor;
553612

554613
/// real &imaginary parts of F(HKL)calc
555614
mutable CrystVector_REAL mFhklCalcReal, mFhklCalcImag ;
@@ -609,7 +668,7 @@ class ScatteringData: virtual public RefinableObj
609668

610669
//Public Clocks
611670
/// Clock for the list of hkl
612-
RefinableObjClock mClockHKL;
671+
mutable RefinableObjClock mClockHKL;
613672
/// Clock for the structure factor
614673
mutable RefinableObjClock mClockStructFactor;
615674
/// Clock for the square modulus of the structure factor
@@ -676,9 +735,9 @@ class ScatteringData: virtual public RefinableObj
676735
mutable RefinableObjClock mClockLuzzatiFactor;
677736
mutable RefinableObjClock mClockFhklCalcVariance;
678737
/// Observed squared structure factors (zero-sized if none)
679-
CrystVector_REAL mFhklObsSq;
738+
mutable CrystVector_REAL mFhklObsSq;
680739
/// Last time observed squared structure factors were altered
681-
RefinableObjClock mClockFhklObsSq;
740+
mutable RefinableObjClock mClockFhklObsSq;
682741
#ifdef __WX__CRYST__
683742
//to access mMaxSinThetaOvLambda
684743
friend class WXDiffractionSingleCrystal;

0 commit comments

Comments
 (0)
Please sign in to comment.