Skip to content

Commit 47fb77e

Browse files
authored
Merge pull request #16 from vincefn/master
Update libobjcryst
2 parents 8382a88 + c71eb53 commit 47fb77e

File tree

9 files changed

+154
-24
lines changed

9 files changed

+154
-24
lines changed

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
# Release notes
22

3+
## Version 2021.1.2 - 2021-11-28
4+
5+
### Added
6+
7+
- Add access to the weight (g/mol) for ScatteringPowerAtom and Crystal
8+
9+
### Changed
10+
11+
- Add relative_length_tolerance and absolute_angle_tolerance_degree to
12+
SpaceGroupExplorer::Run() and RunAll()
13+
- Crystal::XMLInput(): add a hook to re-use atomic scattering power when
14+
mDeleteSubObjInDestructor is False
15+
- Better formula for Crystal and Molecule
16+
17+
### Fixed
18+
19+
- Crystal::XMLInput(): take into account mDeleteSubObjInDestructor.
20+
321
## Version 2021.1.1 - 2021-06-04
422

523
### Added

src/ObjCryst/ObjCryst/Crystal.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,8 @@ void Crystal::Print(ostream &os)const
381381
for(int i=0;i<mScattCompList.GetNbComponent();i++)
382382
nbAtoms += genMult * mScattCompList(i).mOccupancy * mScattCompList(i).mDynPopCorr;
383383
os << " Total number of components (atoms) in one unit cell : " << nbAtoms<<endl
384-
<< " Chemical formula: "<< this->GetFormula() <<endl;
384+
<< " Chemical formula: "<< this->GetFormula() << endl
385+
<< " Weight: "<< this->GetWeight()<< " g/mol" << endl;
385386

386387
VFN_DEBUG_MESSAGE("Crystal::Print():End",5)
387388
}
@@ -408,12 +409,33 @@ std::string Crystal::GetFormula() const
408409
{
409410
if(pos!=velts.begin()) s<<" ";
410411
float nb=pos->second;
411-
if((abs(nb)-nb)<0.01) s<<pos->first<<int(round(nb));
412+
if(abs(round(nb)-nb)<0.005)
413+
{
414+
if(int(round(nb))==1) s<<pos->first;
415+
else s<<pos->first<<int(round(nb));
416+
}
412417
else s<<pos->first<<nb;
413418
}
414419
return s.str();
415420
}
416-
421+
422+
423+
REAL Crystal::GetWeight() const
424+
{
425+
this->GetScatteringComponentList();
426+
if(mScattCompList.GetNbComponent() == 0) return 0;
427+
REAL w=0;
428+
for(unsigned int i=0; i<mScattCompList.GetNbComponent(); ++i)
429+
{
430+
const ScatteringComponent* psi = &mScattCompList(i);
431+
if(psi->mpScattPow == 0) continue;
432+
if(psi->mpScattPow->GetClassName().compare("ScatteringPowerAtom")!=0) continue;
433+
const ScatteringPowerAtom *pat=dynamic_cast<const ScatteringPowerAtom*>(psi->mpScattPow);
434+
w += pat->GetAtomicWeight() * psi->mOccupancy * psi->mDynPopCorr ;
435+
}
436+
return w;
437+
}
438+
417439

418440
CrystMatrix_REAL Crystal::GetMinDistanceTable(const REAL minDistance) const
419441
{

src/ObjCryst/ObjCryst/Crystal.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ class Crystal:public UnitCell
192192

193193
/// Formula with atoms in alphabetic order
194194
std::string GetFormula() const;
195+
/// Weight for the crystal formula, in atomic units (g/mol). This should be
196+
/// multiplied by the spacegroup multiplity to get the unit cell weight.
197+
REAL GetWeight() const;
195198

196199
/** \brief Minimum interatomic distance between all scattering components (atoms) in
197200
* the crystal.
@@ -338,19 +341,26 @@ class Crystal:public UnitCell
338341
const RefinableObjClock& GetClockScattererList()const;
339342

340343
virtual void XMLOutput(ostream &os,int indent=0)const;
344+
/** \brief Input the crystal structure from a stream.
345+
*
346+
* This will destroy any Scatterer of ScatteringPower if
347+
* mDeleteSubObjInDestructor is true. Otherwise they will just
348+
* be de-registered and should be deleted somewhere else,
349+
* but there is a special hook implemented where any
350+
* previously existing ScatteringPowerAtom will be re-used if
351+
* equivalent to the one in the input.
352+
*/
341353
virtual void XMLInput(istream &is,const XMLCrystTag &tag);
342354
//virtual void XMLInputOld(istream &is,const IOCrystTag &tag);
343355

344356
virtual void GlobalOptRandomMove(const REAL mutationAmplitude,
345357
const RefParType *type=gpRefParTypeObjCryst);
346358
virtual REAL GetLogLikelihood()const;
347-
/** \brief output Crystal structure as a cif file (EXPERIMENTAL !)
359+
/** \brief output Crystal structure as a cif file
348360
* \param mindist : minimum distance between atoms to consider them
349361
* overlapping. Overlapping atoms are only included as comments in the
350362
* CIF file.
351363
*
352-
* \warning This is very crude and EXPERIMENTAL so far: there is not much
353-
* information beside atom positions...
354364
*/
355365
virtual void CIFOutput(ostream &os, double mindist = 0.5)const;
356366

src/ObjCryst/ObjCryst/IO.cpp

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -896,13 +896,37 @@ void Crystal::XMLInput(istream &is,const XMLCrystTag &tagg)
896896
this->RemoveSubRefObj(mScatteringPowerRegistry.GetObj(i));
897897
mScatteringPowerRegistry.GetObj(i).DeRegisterClient(*this);
898898
}
899-
mScatteringPowerRegistry.DeleteAll();
899+
900+
std::list<ScatteringPowerAtom*> vold_scattpow;
901+
if(mDeleteSubObjInDestructor)
902+
{
903+
mScatteringPowerRegistry.DeleteAll();
904+
}
905+
else
906+
{
907+
// Keep track of the old atomic scattering powers to see if they can be re-used
908+
for(std::vector<ScatteringPower*>::const_iterator pos=mScatteringPowerRegistry.begin() ;
909+
pos!=mScatteringPowerRegistry.end(); ++pos)
910+
{
911+
if((*pos)->GetClassName().compare("ScatteringPowerAtom")!=0) continue;
912+
vold_scattpow.push_back(dynamic_cast<ScatteringPowerAtom*>(*pos));
913+
}
914+
mScatteringPowerRegistry.DeRegisterAll();
915+
}
916+
900917
for(long i=0;i<mScattererRegistry.GetNb();i++)
901918
{
902919
this->RemoveSubRefObj(mScattererRegistry.GetObj(i));
903920
mScattererRegistry.GetObj(i).DeRegisterClient(*this);
904921
}
905-
mScattererRegistry.DeleteAll();
922+
if(mDeleteSubObjInDestructor)
923+
{
924+
mScattererRegistry.DeleteAll();
925+
}
926+
else
927+
{
928+
mScattererRegistry.DeRegisterAll();
929+
}
906930

907931
for(unsigned int i=0;i<tagg.GetNbAttribute();i++)
908932
{
@@ -1011,6 +1035,33 @@ void Crystal::XMLInput(istream &is,const XMLCrystTag &tagg)
10111035
VFN_DEBUG_MESSAGE("Crystal::XMLInput():reading a ScatteringPowerAtom",5)
10121036
ScatteringPowerAtom *sc=new ScatteringPowerAtom;
10131037
sc->XMLInput(is,tag);
1038+
if(!mDeleteSubObjInDestructor)
1039+
{
1040+
// Can we re-use a previous scattering power since we did not delete them ?
1041+
for(std::list<ScatteringPowerAtom*>::iterator pos= vold_scattpow.begin();
1042+
pos!=vold_scattpow.end();++pos)
1043+
{
1044+
if((*pos)->GetSymbol() != sc->GetSymbol()) continue;
1045+
if((*pos)->GetName() != sc->GetName()) continue;
1046+
if((*pos)->GetFormalCharge() != sc->GetFormalCharge()) continue;
1047+
if((*pos)->GetMaximumLikelihoodNbGhostAtom() != sc->GetMaximumLikelihoodNbGhostAtom()) continue;
1048+
if((*pos)->GetMaximumLikelihoodPositionError() != sc->GetMaximumLikelihoodPositionError()) continue;
1049+
if((*pos)->IsIsotropic() != sc->IsIsotropic()) continue;
1050+
if(fabs((*pos)->GetBiso() - sc->GetBiso()) > 1e-4f) continue;
1051+
if(!(*pos)->IsIsotropic())
1052+
{
1053+
if(fabs((*pos)->GetBij(0) - sc->GetBij(0)) > 1e-4f) continue;
1054+
if(fabs((*pos)->GetBij(1) - sc->GetBij(1)) > 1e-4f) continue;
1055+
if(fabs((*pos)->GetBij(2) - sc->GetBij(2)) > 1e-4f) continue;
1056+
if(fabs((*pos)->GetBij(3) - sc->GetBij(3)) > 1e-4f) continue;
1057+
if(fabs((*pos)->GetBij(4) - sc->GetBij(4)) > 1e-4f) continue;
1058+
if(fabs((*pos)->GetBij(5) - sc->GetBij(5)) > 1e-4f) continue;
1059+
}
1060+
VFN_DEBUG_MESSAGE("Crystal::XMLInput(): reusing scattering power: "<<sc->GetName(),5);
1061+
delete sc;
1062+
sc = *pos;
1063+
}
1064+
}
10141065
this->AddScatteringPower(sc);
10151066
VFN_DEBUG_EXIT("Crystal::XMLInput():reading a ScatteringPowerAtom",5)
10161067
continue;

src/ObjCryst/ObjCryst/Molecule.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,8 +2207,12 @@ std::string Molecule::GetFormula() const
22072207
{
22082208
if(pos!=velts.begin()) s<<" ";
22092209
float nb=pos->second;
2210-
if((abs(nb)-nb)<0.01) s<<pos->first<<int(round(nb));
2211-
else s<<pos->first<<nb;
2210+
if(abs(round(nb)-nb)<0.005)
2211+
{
2212+
if(int(round(nb))==1) s<<pos->first;
2213+
else s<<pos->first<<int(round(nb));
2214+
}
2215+
else s<<pos->first<<nb;
22122216
}
22132217
return s.str();
22142218
}

src/ObjCryst/ObjCryst/PowderPattern.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6825,7 +6825,8 @@ SpaceGroupExplorer::SpaceGroupExplorer(PowderPatternDiffraction *pd):
68256825

68266826
SPGScore SpaceGroupExplorer::Run(const string &spgId, const bool fitprofile,
68276827
const bool verbose, const bool restore_orig,
6828-
const bool update_display)
6828+
const bool update_display, const REAL relative_length_tolerance,
6829+
const REAL absolute_angle_tolerance_degree)
68296830
{
68306831
cctbx::sgtbx::space_group sg;
68316832
try
@@ -6847,11 +6848,13 @@ SPGScore SpaceGroupExplorer::Run(const string &spgId, const bool fitprofile,
68476848
throw ObjCrystException(emsg);
68486849
}
68496850
}
6850-
return this->Run(sg, fitprofile, verbose, restore_orig, update_display);
6851+
return this->Run(sg, fitprofile, verbose, restore_orig, update_display,
6852+
relative_length_tolerance, absolute_angle_tolerance_degree);
68516853
}
68526854

68536855
SPGScore SpaceGroupExplorer::Run(const cctbx::sgtbx::space_group &spg, const bool fitprofile, const bool verbose,
6854-
const bool restore_orig, const bool update_display)
6856+
const bool restore_orig, const bool update_display,
6857+
const REAL relative_length_tolerance, const REAL absolute_angle_tolerance_degree)
68556858
{
68566859
TAU_PROFILE("SpaceGroupExplorer::Run()","void (wxCommandEvent &)",TAU_DEFAULT);
68576860
TAU_PROFILE_TIMER(timer1,"SpaceGroupExplorer::Run()LSQ-P1","", TAU_FIELD);
@@ -6871,7 +6874,7 @@ SPGScore SpaceGroupExplorer::Run(const cctbx::sgtbx::space_group &spg, const boo
68716874
const cctbx::sgtbx::space_group_symbols s = spg.match_tabulated_settings();
68726875
const string hm=s.universal_hermann_mauguin();
68736876
const cctbx::uctbx::unit_cell uc(scitbx::af::double6(a,b,c,d*RAD2DEG,e*RAD2DEG,f*RAD2DEG));
6874-
if(!spg.is_compatible_unit_cell(uc,0.01,0.1))
6877+
if(!spg.is_compatible_unit_cell(uc,relative_length_tolerance,absolute_angle_tolerance_degree))
68756878
{
68766879
throw ObjCrystException("Spacegroup is not compatible with unit cell.");
68776880
}
@@ -6976,7 +6979,8 @@ SPGScore SpaceGroupExplorer::Run(const cctbx::sgtbx::space_group &spg, const boo
69766979
}
69776980

69786981
void SpaceGroupExplorer::RunAll(const bool fitprofile_all, const bool verbose, const bool keep_best,
6979-
const bool update_display, const bool fitprofile_p1)
6982+
const bool update_display, const bool fitprofile_p1,
6983+
const REAL relative_length_tolerance, const REAL absolute_angle_tolerance_degree)
69806984
{
69816985
Crystal *pCrystal=&(mpDiff->GetCrystal());
69826986

@@ -6999,7 +7003,7 @@ void SpaceGroupExplorer::RunAll(const bool fitprofile_all, const bool verbose, c
69997003
cctbx::sgtbx::space_group_symbols s=it.next();
70007004
if(s.number()==0) break;
70017005
cctbx::sgtbx::space_group spg(s);
7002-
if(spg.is_compatible_unit_cell(uc,0.01,0.1)) nbspg++;
7006+
if(spg.is_compatible_unit_cell(uc,relative_length_tolerance, absolute_angle_tolerance_degree)) nbspg++;
70037007
//if(s.universal_hermann_mauguin().size()>hmlen) hmlen=s.universal_hermann_mauguin().size();
70047008
}
70057009
if(verbose) cout << boost::format("Beginning spacegroup exploration... %u to go...\n") % nbspg;
@@ -7018,7 +7022,7 @@ void SpaceGroupExplorer::RunAll(const bool fitprofile_all, const bool verbose, c
70187022
cctbx::sgtbx::space_group_symbols s=it.next();
70197023
if(s.number()==0) break;
70207024
cctbx::sgtbx::space_group spg(s);
7021-
bool compat=spg.is_compatible_unit_cell(uc,0.01,0.1);
7025+
bool compat=spg.is_compatible_unit_cell(uc,relative_length_tolerance,absolute_angle_tolerance_degree);
70227026
if(compat)
70237027
{
70247028
i++;
@@ -7041,8 +7045,9 @@ void SpaceGroupExplorer::RunAll(const bool fitprofile_all, const bool verbose, c
70417045
}
70427046
else
70437047
{
7044-
if(((s.number()==1) && fitprofile_p1) || fitprofile_all) mvSPG.push_back(this->Run(spg, true, false, false, update_display));
7045-
else mvSPG.push_back(this->Run(spg, false, false, true, update_display));
7048+
if(((s.number()==1) && fitprofile_p1) || fitprofile_all) mvSPG.push_back(this->Run(spg, true, false, false, update_display,
7049+
relative_length_tolerance, absolute_angle_tolerance_degree));
7050+
else mvSPG.push_back(this->Run(spg, false, false, true, update_display,relative_length_tolerance,absolute_angle_tolerance_degree));
70467051
if(s.number() == 1) nb_refl_p1 = mvSPG.back().nbreflused;
70477052
mvSPG.back().ngof *= mpDiff->GetNbReflBelowMaxSinThetaOvLambda() / (float)nb_refl_p1;
70487053
mvSPGExtinctionFingerprint.insert(make_pair(fgp, mvSPG.back()));

src/ObjCryst/ObjCryst/PowderPattern.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,22 +1211,31 @@ class SpaceGroupExplorer
12111211
* \param fitprofile: if true, will perform a full profile fitting instead of just Le Bail
12121212
* extraction. Much slower.
12131213
* \param restore_orig: if true, will go back to the original unit cell and spacegroup at the end
1214-
1214+
* \param relative_length_tolerance: relative length tolerance to determine compatible unit cells
1215+
* (i.e. the a/b ratio for quadratic spacegroups)
1216+
* \param absolute_angle_tolerance_degree: the absolute angular tolerance in degrees
1217+
* to determine compatible unit cells.
12151218
* \return: the SPGScore corresponding to this spacegroup
12161219
*/
12171220
SPGScore Run(const string &spg, const bool fitprofile=false, const bool verbose=false,
1218-
const bool restore_orig=false, const bool update_display=true);
1221+
const bool restore_orig=false, const bool update_display=true,
1222+
const REAL relative_length_tolerance=0.01, const REAL absolute_angle_tolerance_degree=0.5);
12191223
/** Run test on a single spacegroup
12201224
*
12211225
* \param spg: the cctbx::sgtbx::space_group
12221226
* \param fitprofile: if true, will perform a full profile fitting instead of just Le Bail
12231227
* extraction. Much slower.
12241228
* \param restore_orig: if true, will go back to the original unit cell and spacegroup at the end
12251229
* \param update_display: if true, update the display during the search
1230+
* \param relative_length_tolerance: relative length tolerance to determine compatible unit cells
1231+
* (i.e. the a/b ratio for quadratic spacegroups)
1232+
* \param absolute_angle_tolerance_degree: the absolute angular tolerance in degrees
1233+
* to determine compatible unit cells.
12261234
* \return: the SPGScore corresponding to this spacegroup
12271235
*/
12281236
SPGScore Run(const cctbx::sgtbx::space_group &spg, const bool fitprofile=false,
1229-
const bool verbose=false, const bool restore_orig=false, const bool update_display=true);
1237+
const bool verbose=false, const bool restore_orig=false, const bool update_display=true,
1238+
const REAL relative_length_tolerance=0.01, const REAL absolute_angle_tolerance_degree=0.5);
12301239
/** Run test on all spacegroups compatible with the unit cell
12311240
* Note that all scores's ngof values will be multiplied by nb_refl/nb_refl_P1 to
12321241
* have a better indicator of the quality taking into account the number of reflections used.
@@ -1238,10 +1247,15 @@ class SpaceGroupExplorer
12381247
* \param keep_best: if true, will keep the best solution at the end (default: restore the original one)
12391248
* \param update_display: if true, update the display during the search
12401249
* \param fitprofile_p1: if true, fit the profile for p1 (ignored if fitprofile_all=true)
1250+
* \param relative_length_tolerance: relative length tolerance to determine compatible unit cells
1251+
* (i.e. the a/b ratio for quadratic spacegroups)
1252+
* \param absolute_angle_tolerance_degree: the absolute angular tolerance in degrees
1253+
* to determine compatible unit cells.
12411254
* \return: the SPGScore corresponding to this spacegroup
12421255
*/
12431256
void RunAll(const bool fitprofile_all=false, const bool verbose=true, const bool keep_best=false,
1244-
const bool update_display=true, const bool fitprofile_p1=true);
1257+
const bool update_display=true, const bool fitprofile_p1=true,
1258+
const REAL relative_length_tolerance=0.01, const REAL absolute_angle_tolerance_degree=0.5);
12451259
/// Get the list of all scores obatined after using RunAll()
12461260
const list<SPGScore>& GetScores() const;
12471261
private:

src/ObjCryst/ObjCryst/ScatteringPower.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ void ScatteringPowerAtom::Init(const string &name,const string &symbol,const REA
366366

367367
cctbx::eltbx::tiny_pse::table tpse(mSymbol);
368368
mAtomicNumber=tpse.atomic_number();
369+
mAtomicWeight=tpse.weight();
369370

370371
cctbx::eltbx::icsd_radii::table ticsd(mSymbol);
371372
mRadius= ticsd.radius();
@@ -781,6 +782,7 @@ string ScatteringPowerAtom::GetElementName() const
781782
}
782783

783784
int ScatteringPowerAtom::GetAtomicNumber() const {return mAtomicNumber;}
785+
REAL ScatteringPowerAtom::GetAtomicWeight() const {return mAtomicWeight;}
784786
REAL ScatteringPowerAtom::GetRadius() const {return mRadius;}
785787
REAL ScatteringPowerAtom::GetCovalentRadius() const {return mCovalentRadius;}
786788
unsigned int ScatteringPowerAtom::GetMaxCovBonds()const{ return mMaxCovBonds;}

src/ObjCryst/ObjCryst/ScatteringPower.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,10 @@ class ScatteringPowerAtom:virtual public ScatteringPower
381381
*which uses data from the CRC Handbook of Chemistry & Physics, 63rd & 70th editions
382382
*/
383383
string GetElementName() const;
384-
///Atomic number for this atom
384+
/// Atomic number for this atom
385385
int GetAtomicNumber() const;
386+
/// Atomic weight (g/mol) for this atom
387+
REAL GetAtomicWeight() const;
386388
/// Atomic radius for this atom or ion, in Angstroems (ICSD table from cctbx)
387389
REAL GetRadius() const;
388390
/// Covalent Radius for this atom, in Angstroems (from cctbx)
@@ -412,6 +414,8 @@ class ScatteringPowerAtom:virtual public ScatteringPower
412414
string mSymbol;
413415
/// atomic number (Z) for the atom
414416
int mAtomicNumber;
417+
/// atomic weight (g/mol) for the atom
418+
REAL mAtomicWeight;
415419

416420
/** Pointer to cctbx's gaussian describing the thomson x-ray
417421
* scattering factor.

0 commit comments

Comments
 (0)