Skip to content

feat(cpp): add cleed++ library#59

Open
Liam-Deacon wants to merge 6 commits intomasterfrom
feat/issue-48-cleedpp
Open

feat(cpp): add cleed++ library#59
Liam-Deacon wants to merge 6 commits intomasterfrom
feat/issue-48-cleedpp

Conversation

@Liam-Deacon
Copy link
Owner

@Liam-Deacon Liam-Deacon commented Dec 24, 2025

Problem

Issue #48 requests bringing the cleed++ C++ library from develop into master, adding a build toggle, and ensuring C/C++ interoperability for public headers.

Solution

  • Port src/cleed++ from develop and gate it with BUILD_CPP_BINDINGS.
  • Install cleed++ headers under include/cleed++ and build a small cleedpp_smoke executable linked against both the C and C++ libraries.
  • Add extern "C" guards to public C headers that were missing them.
  • Document the experimental C++ API and build instructions in Sphinx docs.

Testing

  • Not run (build-only change).

Follow-ups

  • Confirm whether to keep the qmake/Eclipse metadata from develop (*.pri, .project, .cproject, .settings).
  • Decide whether to install C headers as part of the public ABI (currently only cleed++ headers are installed).
  • Define a stable C API facade and document ABI guarantees.

Summary by Sourcery

Add an optional experimental C++ bindings library and ensure C headers are usable from C++.

New Features:

  • Introduce a cleed++ C++ library with core LEED, R-factor, search, and utility classes, plus a cleedpp_smoke example binary.
  • Expose a CMake option to enable or disable building the experimental C++ bindings.

Enhancements:

  • Add C-compatible extern "C" guards to public C headers to support inclusion from C++ code.

Documentation:

  • Add Sphinx documentation describing the experimental C++ API and how to build it.

Port the cleed++ sources from develop, gate the build with BUILD_CPP_BINDINGS, and add a small C++ smoke executable. Ensure C headers are C++-safe and document the experimental C++ API.
@coderabbitai
Copy link

coderabbitai bot commented Dec 24, 2025

Warning

Rate limit exceeded

@Liam-Deacon has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 24 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 1829011 and 83f8770.

📒 Files selected for processing (110)
  • CMakeLists.txt
  • doc/cpp_bindings.rst
  • doc/index.rst
  • src/CMakeLists.txt
  • src/cleed++/.cproject
  • src/cleed++/.gitignore
  • src/cleed++/.project
  • src/cleed++/.settings/language.settings.xml
  • src/cleed++/.settings/org.eclipse.cdt.managedbuilder.core.prefs
  • src/cleed++/AoIRFactor.h
  • src/cleed++/BulkModel.hh
  • src/cleed++/CMakeLists.txt
  • src/cleed++/Core/Atom.cc
  • src/cleed++/Core/Atom.hh
  • src/cleed++/Core/BaseElement.cc
  • src/cleed++/Core/BaseElement.hh
  • src/cleed++/Core/BasicElement.cc
  • src/cleed++/Core/BasicElement.hh
  • src/cleed++/Core/Basis.cc
  • src/cleed++/Core/Basis.hh
  • src/cleed++/Core/Coordinate.cc
  • src/cleed++/Core/Coordinate.hh
  • src/cleed++/Core/Element.cc
  • src/cleed++/Core/Element.hh
  • src/cleed++/Core/MillerIndex.cc
  • src/cleed++/Core/MillerIndex.hh
  • src/cleed++/Core/core.pri
  • src/cleed++/IVCurve.cc
  • src/cleed++/IVCurve.hh
  • src/cleed++/IVCurvePair.cc
  • src/cleed++/IVCurvePair.hh
  • src/cleed++/LEED/ChangeLog
  • src/cleed++/LEED/Crystal.cc
  • src/cleed++/LEED/Crystal.hh
  • src/cleed++/LEED/LEED.hh
  • src/cleed++/LEED/LEEDAtom.hh
  • src/cleed++/LEED/Layer.cc
  • src/cleed++/LEED/Layer.hh
  • src/cleed++/LEED/PhaseShift.cc
  • src/cleed++/LEED/PhaseShift.hh
  • src/cleed++/LEED/leed.pri
  • src/cleed++/Model.hh
  • src/cleed++/Pattern/Pattern.hh
  • src/cleed++/RFactor/RFactor.cc
  • src/cleed++/RFactor/RFactor.hh
  • src/cleed++/RFactor/RFactorArgs.cc
  • src/cleed++/RFactor/RFactorArgs.hh
  • src/cleed++/RFactor/rfactor.pri
  • src/cleed++/Search/Search.cc
  • src/cleed++/Search/Search.hh
  • src/cleed++/Search/SearchAtom.cc
  • src/cleed++/Search/SearchAtom.hh
  • src/cleed++/Search/search.pri
  • src/cleed++/Util/streamredirecter.hh
  • src/cleed++/Util/teebuf.hh
  • src/cleed++/Util/teestream.cc
  • src/cleed++/Util/teestream.hh
  • src/cleed++/cleed++.pro
  • src/cleed++/examples/cleedpp_smoke.cc
  • src/cleed++/rfac.pri
  • src/include/basis.h
  • src/include/basis_vector.h
  • src/include/cleed_cstring.h
  • src/include/cleed_string.h
  • src/include/coord.h
  • src/include/gh_stddef.h
  • src/include/latt.h
  • src/include/latt.h.in
  • src/include/lattice.h
  • src/include/leed_def.h
  • src/include/malloc.h
  • src/include/matrix_2x2.h
  • src/include/miller_index.h
  • src/include/patt_ver.h
  • src/include/pattern.h
  • src/include/qm.h
  • src/include/real.h
  • src/include/rfac_def.h
  • src/include/rfac_func.h
  • src/include/rfac_ver.h
  • src/include/rfac_ver.h.in
  • src/include/search_def.h
  • src/include/spots.h
  • src/latt/CMakeLists.txt
  • src/latt/latt_streams.c
  • src/latt/lattice.c
  • src/rfac/CMakeLists.txt
  • src/rfac/Makefile.am
  • src/rfac/rfac.c
  • src/rfac/rfac_ivcur.c
  • src/rfac/rfgetsa.c
  • src/rfac/rfhelp.c
  • src/rfac/rfinput.c
  • src/rfac/rfintindl.c
  • src/rfac/rflines.c
  • src/rfac/rflorentz.c
  • src/rfac/rfmklide.c
  • src/rfac/rfmklist.c
  • src/rfac/rfr1.c
  • src/rfac/rfr2.c
  • src/rfac/rfrb.c
  • src/rfac/rfrdargs.c
  • src/rfac/rfrdcleed.c
  • src/rfac/rfrdexpt.c
  • src/rfac/rfrmin.c
  • src/rfac/rfrp.c
  • src/rfac/rfsort.c
  • src/rfac/rfspline.c
  • src/rfac/rfsplint.c
  • src/rfac/rfversion.c

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Dec 24, 2025

Reviewer's Guide

Adds an experimental C++ wrapper library (cleed++) around existing CLEED C APIs, gated by a new BUILD_CPP_BINDINGS CMake option, wires it into the build/install (including a small smoke executable), and updates several public C headers with extern "C" guards for C++ consumers plus initial Sphinx documentation for the bindings.

Class diagram for core chemistry and geometry types in cleed++

classDiagram

  class BaseElement {
    +BaseElement()
    +BaseElement(size_t atomicNumber)
    +BaseElement(string name)
    +BaseElement(char symbol[])
    +size_t getAtomicNumber() const
    +string getElementName() const
    +string getElementSymbol() const
    +void setAtomicNumber(size_t Z)
    +void setElementName(string name)
    +void setElementSymbol(char symbol[])
    -size_t atomicNumber
    -string name
    -char symbol
  }

  class BasicElement {
    <<concrete>>
    +enum atomicNumber
    +BasicElement()
    +BasicElement(unsigned int Z)
    +BasicElement(string name)
    +bool operator!()
    +BasicElement operator=(string id)
    +BasicElement operator=(int Z)
    +BasicElement operator-(int Z)
    +BasicElement operator+(int Z)
    +bool operator==(BasicElement other)
    +bool operator==(string element)
    +bool operator!=(BasicElement other)
    +bool operator!=(string element)
    +bool operator<(BasicElement other)
    +bool operator>(BasicElement other)
    +bool operator<=(BasicElement other)
    +bool operator>=(BasicElement other)
    +int getAtomicNumber() const
    +string getName() const
    +string getSymbol() const
    +BasicElement setAtomicNumber(size_t Z)
    +BasicElement setName(string name)
    +BasicElement setSymbol(string symbol)
    -unsigned int Z
    -string name
    -string symbol
    +static map~string,unsigned int~ NAMES
    +static map~string,unsigned int~ SYMBOLS
    +static map~string,BasicElement~ ELEMENTS
  }

  class Element {
    <<concrete>>
    +Element(int Z,string symbol,string name)
    +int getGroup() const
    +int getPeriod() const
    +char getBlock() const
    +int getSeries() const
    +double getMolarMass() const
    +double getElectronegivity() const
    +double getElectronAffinity() const
    +double getCovalentRadius() const
    +double getAtomicRadius() const
    +double getVanDerWaalsRadius() const
    +double getBoilingPoint() const
    +double getMeltingPoint() const
    +double getDensity() const
    +string getElectronConfiguration() const
    +string getOxidationStates() const
    +vector~double~ getIonisationEnergies() const
    +string getDescription() const
    +Element setGroup(int group)
    +Element setGroup(string group)
    +Element setPeriod(int period)
    +Element setPeriod(string period)
    +Element setBlock(int block)
    +Element setBlock(char block)
    +Element setSeries(int series)
    +Element setSeries(string series)
    +Element setMolarMass(double mass)
    +Element setElectronegativity(double electronegativity)
    +Element setElectronAffinity(double electronAffinity)
    +Element setCovalentRadius(double covalentRadius)
    +Element setAtomicRadius(double atomicRadius)
    +Element setVanDerWaalsRadius(double vdwRadius)
    +Element setBoilingPoint(double tboil)
    +Element setMeltingPoint(double tmelt)
    +Element setDensity(double density)
    +Element setElectronConfiguration(string config)
    +Element setOxidationStates(string oxidationStates)
    +Element setIonisationEnergies(vector~double~ ionEnergies)
    +Element setDescription(string description)
    -int group
    -int period
    -char block
    -int series
    -double molarMass
    -double electronegativity
    -double electronAffinity
    -double covalentRadius
    -double atomicRadius
    -double vdwRadius
    -double boilingPoint
    -double meltingPoint
    -double density
    -double relativeAbundance
    -string eletronConfig
    -string oxidationStates
    -vector~double~ ionisationEnergies
    -string description
    +static map~int,char~ PERIODS
    +static vector~char~ BLOCKS
    +static map~int,string~ SERIES
    +static map~int,tuple~string,string~~ GROUPS
    +static map~int,string~ DESCRIPTIONS
  }

  class Atom {
    <<abstract>>
    +Atom()
    +Atom(double x,double y,double z)
    +Atom(vector~double~ pos)
    +double getXPosition() const
    +double getYPosition() const
    +double getZPosition() const
    +vector~double~ getPosition() const
    +Atom setXPosition(double x_pos)
    +Atom setYPosition(double y_pos)
    +Atom setZPosition(double z_pos)
    +Atom setPosition(vector~double~ pos)
    -double x
    -double y
    -double z
  }

  class Coordinate {
    +coord *pos
    +Coordinate()
    +Coordinate(double x,double y,double z)
    +Coordinate(Coordinate position)
    +Coordinate(coord *position)
    +Coordinate setX(double x)
    +Coordinate setY(double y)
    +Coordinate setZ(double z)
    +Coordinate setCoordinate(double x,double y,double z)
    +Coordinate setCoordinate(Coordinate position)
    +Coordinate setCoordinate(coord *position)
    +double getMagnitude()
    +double getX()
    +double getY()
    +double getZ()
    +coord *get_coord()
    +void print(FILE *f)
  }

  class Basis {
    +basis *basis_ptr
    +Basis()
    +Basis(basis *a)
    +Basis(Basis a)
    +Basis setA1(Coordinate a1)
    +Basis setA1(double a1_x,double a1_y,double a1_z)
    +Basis setA2(Coordinate a2)
    +Basis setA2(double a2_x,double a2_y,double a2_z)
    +Basis setA3(Coordinate a3)
    +Basis setA3(double a3_x,double a3_y,double a3_z)
    +Basis setBasis(Coordinate a1,Coordinate a2,Coordinate a3)
    +Basis setBasis(Basis basis)
    +Basis setBasis(Basis *basis)
    +Coordinate getA1() const
    +Coordinate getA2() const
    +Coordinate getA3() const
  }

  class MillerIndex {
    +MillerIndex(double h,double k,double l)
    +MillerIndex(miller_hkl *hkl)
    +double getMillerH() const
    +double getMillerK() const
    +double getMillerL() const
    +void getMillerIndices(double h,double k,double l) const
    +string getMillerIndicesAsString() const
    +MillerIndex setMillerH(double h)
    +MillerIndex setMillerK(double k)
    +MillerIndex setMillerL(double l)
    +MillerIndex setMillerIndices(double h,double k,double l)
    -double h
    -double k
    -double l
  }

  class Model {
  }

  class BulkModel {
  }

  class invalidElementException {
    +invalidElementException(char *msg)
    +~invalidElementException()
    +char *what() const
    -string err_msg
  }

  BaseElement <|-- BasicElement
  BasicElement <|-- Element
  BaseElement <|-- Atom
  Element ..|> BasicElement
  Atom ..|> BaseElement
  BulkModel --|> Model
  invalidElementException ..|> std_exception
Loading

Class diagram for LEED and crystal modelling types in cleed++

classDiagram

  class LEED {
    +LEED()
    +~LEED()
  }

  class Crystal {
    <<wraps leed_crystal>>
    +Crystal()
    +Crystal(leed_crystal *crystal_ptr)
    +Crystal(Crystal crystal)
    +~Crystal()
    +bool operator==(Crystal other) const
    +bool operator!=(Crystal other) const
    +bool operator==(leed_crystal *other) const
    +bool operator!=(leed_crystal *other) const
    +double getRealOpticalPotential() const
    +double getImaginaryOpticalPotential() const
    +double getTemperature() const
    +size_t getNumberOfRotationalSymmetries() const
    +vector~double~ getAxisOfRotationalSymmetry() const
    +size_t getNumberOfMirrorPlanes() const
    +real *getMirrorPlaneGeometryPtr() const
    +vector~double~ getMirrorPlaneGeometry() const
    +leed_mirror_sym getMirrorSymmetry() const
    +real *getAngleAlphaDegreesPtr() const
    +vector~double~ getAngleAlphaDegrees() const
    +vector~double~ getSubstrateBasisVectors() const
    +double getSubstrateUnitCellArea() const
    +vector~double~ getSuperstructureBasisVectors() const
    +double getSuperstructureRelativeUnitCellArea() const
    +size_t getNumberOfLayers() const
    +leed_layer *getLayersPtr() const
    +vector~leed_layer~ getLayers() const
    +double getMinimumInterlayerDistance() const
    +size_t getNumberOfAtoms() const
    +size_t getNumberOfTypes() const
    +vector~string~ getComments() const
    +void setRealOpticalPotential(double vr)
    +void setImaginaryOpticalPotential(double vi)
    +void setTemperature(double temp)
    +void setNumberOfRotationalSymmetries(size_t n_rot)
    +void setAxisOfRotationalSymmetry(vector~double~ rot_axis)
    +void setAxisOfRotationalSymmetry(double *rot_axis,size_t n)
    +void setNumberOfMirrorPlanes(size_t n_mir)
    +void setMirrorPlaneGeometry(vector~double~ m_plane)
    +void setMirrorPlaneGeometry(double *m_plane,size_t n)
    +void setMirrorSymmetry(leed_mirror_sym symmetry)
    +void setAngleAlphaDegrees(vector~double~ alpha)
    +void setAngleAlphaDegrees(double *alpha,size_t n)
    +void setSubstrateBasisVectors(vector~double~ a)
    +void setSubstrateUnitCellArea(double area)
    +void setSuperstructureBasisVectors(vector~double~ b)
    +void setSuperstructureRelativeUnitCellArea(double rel_area)
    +void setNumberOfLayers(size_t n_layers)
    +void setLayers(vector~leed_layer~ layers)
    +void setLayers(leed_layer *layers,size_t n_layers)
    +void setMinimumInterlayerDistance(double d_min)
    +void setNumberOfAtoms(size_t n_atoms)
    +void setNumberOfTypes(size_t n_types)
    +void setComments(vector~string~ comments)
    +void setComments(char **comments,size_t n_comments)
  }

  class Layer {
    <<wraps leed_layer>>
    +Layer()
    +Layer(leed_layer *layer)
    +~Layer()
    +bool isPeriodic()
    +size_t getLayerNumber()
    +size_t getNumberOfAtoms()
    +leed_structure getLayerType()
    +vector~real~ getA1()
    +vector~real~ getA2()
    +vector~vector~real~~ getBasis()
    +real getRelativeArea()
    +vector~vector~real~~ getRegistryShift()
    +vector~vector~real~~ getVectorFromLast()
    +vector~vector~real~~ getVectorToNext()
    +vector~Atom~ getAtomList()
    +Layer setPeriodic(bool periodic)
    +Layer setLayerNumbers(size_t number)
    +Layer setLayerType(leed_structure type)
    +Layer setA1(real a1x,real a1y)
    +Layer setA2(real a2x,real a2y)
    +Layer setRelativeArea(real area)
    +Layer setAtoms(vector~Atom~ atomList)
    +Layer setAtoms(leed_atom *atoms,size_t n)
    +Layer setAtom(leed_atom *atom,int index)
    +Layer setAtom(LEEDAtom atom,int index)
  }

  class LEEDAtom {
    <<wraps leed_atom, extends Atom>>
    +LEEDAtom()
    +LEEDAtom(LEEDAtom other)
    +~LEEDAtom()
    +LEEDAtom operator=(LEEDAtom other)
    +bool operator==(LEEDAtom other) const
    +bool operator!=(LEEDAtom other) const
    +size_t getLayerNumber()
    +leed_structure getStructureType()
    +leed_matrix_diag getMatrixType()
    +real getDebyeWallerFactor()
    +double getXPosition() const
    +double getYPosition() const
    +double getZPosition() const
    +vector~double~ getPosition() const
    +LEEDAtom setLayerNumber(size_t number)
    +LEEDAtom setMatrixType(leed_matrix_diag type)
    +LEEDAtom setStructureType(leed_structure structure)
    +LEEDAtom setDebyeWallerFactor(real dwf)
    +LEEDAtom setXPosition(double x_pos)
    +LEEDAtom setYPosition(double y_pos)
    +LEEDAtom setZPosition(double z_pos)
    +LEEDAtom setPosition(vector~double~ pos)
  }

  class PhaseShift {
    <<wraps leed_phase>>
    +PhaseShift()
    +PhaseShift(leed_phase *phsh_ptr)
    +PhaseShift(string inputFile)
    +~PhaseShift()
    +PhaseShift operator+(PhaseShift phsh)
    +int getLmax() const
    +leed_matrix_diag getMatrixType() const
    +real getMaxEnergy() const
    +real getMinEnergy() const
    +vector~real~ getEnergyList() const
    +vector~real~ getPhaseShiftValuesList() const
    +vector~real~ getDeltaRList() const
    +size_t getNumberOfEnergies() const
    +PhaseShift setLmax(int lmax)
    +PhaseShift setMatrixType(leed_matrix_diag Type)
    +PhaseShift setMaxEnergy(real Emax)
    +PhaseShift setMinEnergy(real Emin)
    +PhaseShift setInputFile(string filepath)
    +PhaseShift setInputFile(char *filepath)
    +PhaseShift setData(real *energies_ptr,real *phaseshifts_ptr,size_t n)
    +PhaseShift setData(vector~real~ energies,vector~real~ phaseshifts)
    +PhaseShift setDeltaR(vector~real~ dr)
    +PhaseShift setDeltaR(real dr[4])
    +void setDataFromFile()
  }

  class Pattern {
    <<wraps pattern>>
    +Pattern()
    +Pattern(Pattern other)
    +Pattern(pattern *pattern_ptr)
    +~Pattern()
    +string getTitle()
    +size_t getNumberOfDomains()
    +double getRadius()
    +vector~double~ getBasisVectorA1()
    +vector~double~ getBasisVectorA2()
    +vector~Matrix2x2~ getSuperStructureMatrices()
    +bool isSquare()
    +void setTitle(string title)
    +void setBasisVectorA1(double x,double y)
    +void setBasisVectorA2(double x,double y)
    +int setNumberOfDomains(size_t n_dom)
    +void setRadius(double radius)
    +void setSuperStructureMatrix(Matrix2x2 *mat,size_t domain)
    +void setSquare(bool isSquare)
  }

  Atom <|-- LEEDAtom
  Crystal "1" o-- "*" Layer : aggregates
  Layer "1" o-- "*" LEEDAtom : contains
Loading

Class diagram for RFactor, IV curves, and search wrappers in cleed++

classDiagram

  class IVCurve {
    <<wraps rfac_iv>>
    -rfac_iv *iv_ptr
    -string comments
    +IVCurve()
    +IVCurve(rfac_iv iv)
    +IVCurve(string ivFilePath)
    +IVCurve(IVCurve ivCurve)
    +~IVCurve()
    +IVCurve operator=(IVCurve other)
    +bool operator==(IVCurve other) const
    +bool operator!=(IVCurve other) const
    +IVCurve setIVData(rfac_iv_data iv_data,size_t n)
    +IVCurve setIVData(vector~real~ x,vector~real~ y,vector~real~ deriv2)
    +IVCurve sort()
    +IVCurve smooth(double vi)
    +IVCurve spline()
    +IVCurve setInitialEnergy(double e_0)
    +IVCurve setLastEnergy(double e_n)
    +IVCurve setMaximumIntensity(double maxI)
    +void writeIVData(string ivFilePath)
    +rfac_iv_data *getRfacIVData() const
    +void getIVData(vector~real~ x,vector~real~ y,vector~real~ deriv2) const
    +bool isEquiDistant() const
    +bool isSorted() const
    +bool isSmoothed() const
    +bool isSplined() const
    +double getInitialEnergy() const
    +double getLastEnergy() const
    +double getMaximumIntensity() const
    +rfac_iv *get_rfac_iv_ptr() const
    +void readIVData(string ivFilePath)
  }

  class IVCurvePair {
    -rfac_ivcur *iv_pair
    +IVCurvePair(IVCurvePair other)
    +IVCurvePair(rfac_ivcur *ivcur_ptr)
    +IVCurvePair(IVCurve theory,IVCurve experimental)
    +~IVCurvePair()
    +double getWeighting() const
    +double getEnergyOfFirstAppearance() const
    +double getOverlap() const
    +int getGroupID() const
    +rfac_ivcur *getIVPairPtr() const
    +void calculateOverlap()
    +IVCurvePair setWeighting(double weight)
    +IVCurvePair setSpotID(rfac_spot *spot)
    +IVCurvePair setTheoryIVCurve(IVCurve theory)
    +IVCurvePair setExperimentalIVCurve(IVCurve experimental)
  }

  class RFactorArgs {
    <<wraps rfac_args>>
    -rfac_args c_args
    +RFactorArgs(RFactorArgs other)
    +RFactorArgs(int argc,char *argv[])
    +RFactorArgs(rfac_args *args_ptr)
    +RFactorArgs(string ctrFile,string theoryFile,rfactor_type type,double initialEnergyShift,double finalEnergyShift,double energyShiftStep,double vi,bool allGroups,char *ivOutputFile,char *outputFile)
    +~RFactorArgs()
    +RFactorArgs operator=(RFactorArgs other)
    +RFactorArgs operator=(rfac_args *args_ptr)
    +string getControlFile() const
    +string getTheoryFile() const
    +string getOutputFile() const
    +string getIVOutputFile() const
    +rfactor_type getRFactorType() const
    +double getInitialEnergyShift() const
    +double getFinalEnergyShift() const
    +double getEnergyShiftStep() const
    +double getOpticalPotential() const
    +bool getAllGroups() const
    +void setControlFile(string ctrFile)
    +void setTheoryFile(string theoryFile)
    +void setOutputFile(string outputFile)
    +void setIVOutputFile(string ivOutputFile)
    +void setRFactorType(rfactor_type type)
    +void setInitialEnergyShift(double dE0)
    +void setFinalEnergyShift(double dEf)
    +void setEnergyShiftStep(double dEs)
    +void setOpticalPotential(double vi)
    +void setAllGroups(bool allGroups)
  }

  class RFactor {
    -vector~IVCurvePair~ iv_datasets
    -RFactorArgs args
    -double rfactor
    -double relativeError
    -double iRatio
    -double energyShift
    -double energyRange
    +RFactor(string control_filepath,string theory_filepath)
    +~RFactor()
    +bool operator==(RFactor other) const
    +bool operator!=(RFactor other) const
    +void calculateRFactor()
    +void updateIVs(string control_filepath,string theory_filepath)
    +void updateIVs(vector~IVCurvePair~ ivs)
    +double getRFactor() const
    +double getRR() const
    +double getTotalEnergyRange() const
    +double getTheoryToExperimentalIntegralRatio() const
    +double getMinimumEnergyShift() const
  }

  class SearchAtom {
    <<wraps search_atom, extends Atom>>
    +SearchAtom()
    +SearchAtom(SearchAtom other)
    +~SearchAtom()
    +int getType() const
    +size_t getNumberOfEquivalentAtoms() const
    +size_t getReferenceToSymmetryEquivalentAtom() const
    +string getAtomName() const
    +double getMinimumRadius() const
    +double getDeltaR() const
    +double getXPosition() const
    +double getYPosition() const
    +double getZPosition() const
    +vector~double~ getPosition() const
    +vector~double~ getXShifts()
    +vector~double~ getYShifts()
    +vector~double~ getZShifts()
    +vector~double~ getDeltaRShifts()
    +void setType(int type)
    +void setNumberOfEquivelentAtoms(size_t ref)
    +void setReferenceToSymmetryEquivalentAtom(size_t n_ref)
    +void setAtomName(char *name)
    +void setAtomName(string name)
    +void setMinimumRadius(double r_min)
    +void setXPosition(double x_pos)
    +void setYPosition(double y_pos)
    +void setZPosition(double z_pos)
    +void setPosition(vector~double~ pos)
  }

  class Search {
    -search c_search
    -RFactor *rfactor_ptr
    -LEED *leed_ptr
    -string theory_filepath
    -string control_filepath
    +Search(string control_filepath,string theory_filepath,search_method driver)
    +~Search()
    +size_t getNumberOfIndependentParameters() const
    +size_t getNumberOfGeometricalParameters() const
    +double getMinimumX() const
    +double getMinimumY() const
    +double getMinimumZ() const
    +double getMaximumX() const
    +double getMaximumY() const
    +double getMaximumZ() const
    +vector~double~ getBasis() const
    +bool isAngleSearch() const
    +size_t getNumberOfThetaParameters() const
    +size_t getNumberOfPhiParameters() const
    +double getInitialThetaValue() const
    +double getInitialPhiValue() const
    +bool isZOnlySearch() const
    +size_t getNumberOfRotationalSymmetries() const
    +vector~double~ getRotationalAxis() const
    +vector~double~ getMirrorPlanePoint() const
    +vector~double~ getMirrorPlaneDirection() const
    +string getRFactorType() const
    +double getRFactorShiftRange() const
    +RFactor *getRFactor() const
    +void setNumberOfIndependentParameters(size_t n_par)
    +void setNumberOfGeometricalParameters(size_t n_geo)
    +void setMinimumX(double x_min)
    +void setMinimumY(double y_min)
    +void setMinimumZ(double z_min)
    +void setMaximumX(double x_max)
    +void setMaximumY(double y_max)
    +void setMaximumZ(double z_max)
    +void setBasis(vector~double~ basis)
    +void setAngleSearch(bool angle)
    +void setNumberOfThetaParameters(size_t n_theta)
    +void setNumberOfPhiParameters(size_t n_phi)
    +void setInitialThetaValue(double theta_0)
    +void setInitialPhiValue(double phi_0)
    +void setZOnlySearch(bool z_only)
    +void setNumberOfRotationalSymmetries(size_t n_rot)
    +void setRotationalAxis(vector~double~ rot_axis)
    +void setMirrorPlanePoint(vector~double~ mir_point)
    +void setMirrorPlaneDirection(vector~double~ mir_dir)
    +void setRFactorType(string type)
    +void setRFactorType(char *type)
    +void setRFactorShiftRange(double range)
    +void setRFactor(RFactor rfac)
    +void setTheoryFilePath(string theory_filepath)
    +void setControlFilePath(string control_filepath)
    +void startSearch()
    +void stopSearch()
    +void resumeSearch()
  }

  class AoIRFactor {
    <<specialised RFactor (angle of incidence)>>
  }

  Atom <|-- SearchAtom
  IVCurvePair "1" o-- "1" IVCurve : theory
  IVCurvePair "1" o-- "1" IVCurve : experimental
  RFactor "1" o-- "*" IVCurvePair : uses
  RFactor "1" o-- "1" RFactorArgs : configuredBy
  Search "1" o-- "1" RFactor : owns
  AoIRFactor --|> RFactor
Loading

File-Level Changes

Change Details Files
Add CMake option and build wiring for the experimental cleed++ C++ library and smoke test binary.
  • Introduce BUILD_CPP_BINDINGS option in the top-level CMake configuration, defaulting to OFF.
  • Conditionally add src/cleed++ as a subdirectory from src/CMakeLists.txt when BUILD_CPP_BINDINGS is enabled.
  • Define shared and static cleed++ libraries from all C++ sources in src/cleed++, with consistent OUTPUT_NAME for shared/static variants.
  • Link cleed++ libraries against the math library and expose appropriate include directories for consumers.
  • Add a cleedpp_smoke executable in src/cleed++/examples that links against cleed++ and the existing search C library as a basic linkage smoke test.
CMakeLists.txt
src/CMakeLists.txt
src/cleed++/CMakeLists.txt
src/cleed++/examples/cleedpp_smoke.cc
Ensure C/C++ interoperability for selected public C headers via extern "C" guards.
  • Wrap function and type declarations in several public headers with conditional extern "C" guards when compiled under C++.
  • Guard inclusion of system malloc compatibility header with extern "C" to keep linkage C-compatible.
  • Keep existing header structure and macros intact while only adding the guards at top and bottom of the headers.
src/include/latt.h
src/include/basis_vector.h
src/include/cleed_cstring.h
src/include/cleed_string.h
src/include/malloc.h
src/include/patt_ver.h
src/include/qm.h
src/include/latt.h.in
Port and add the cleed++ C++ wrapper library sources around the legacy CLEED C APIs.
  • Introduce C++ wrapper classes for core concepts (coordinates, basis vectors, atoms/elements, Miller indices, crystals, layers, LEED models, IV curves, R-factor computation, search parameters, and pattern data) that subclass or wrap existing C structs.
  • Provide thin RAII wrappers that allocate/free underlying C resources (e.g., coord, basis, rfac_iv, search, leed_phase structures) and expose C++-style getters/setters and operators.
  • Add several higher-level helper classes like IVCurvePair, RFactorArgs, Model/BulkModel, and LEED, plus small utility types for stream teeing/redirecting.
  • Include some partially implemented or placeholder methods that will need follow-up review for correctness, exception safety, and adherence to modern C++ practices.
src/cleed++/Core/Coordinate.hh
src/cleed++/Core/Coordinate.cc
src/cleed++/Core/Basis.hh
src/cleed++/Core/Basis.cc
src/cleed++/Core/Atom.hh
src/cleed++/Core/Atom.cc
src/cleed++/Core/BaseElement.hh
src/cleed++/Core/BaseElement.cc
src/cleed++/Core/BasicElement.hh
src/cleed++/Core/BasicElement.cc
src/cleed++/Core/Element.hh
src/cleed++/Core/Element.cc
src/cleed++/Core/MillerIndex.hh
src/cleed++/Core/MillerIndex.cc
src/cleed++/LEED/Crystal.hh
src/cleed++/LEED/Crystal.cc
src/cleed++/LEED/Layer.hh
src/cleed++/LEED/Layer.cc
src/cleed++/LEED/LEEDAtom.hh
src/cleed++/LEED/PhaseShift.hh
src/cleed++/LEED/PhaseShift.cc
src/cleed++/LEED/LEED.hh
src/cleed++/IVCurve.hh
src/cleed++/IVCurve.cc
src/cleed++/IVCurvePair.hh
src/cleed++/IVCurvePair.cc
src/cleed++/RFactor/RFactor.hh
src/cleed++/RFactor/RFactor.cc
src/cleed++/RFactor/RFactorArgs.hh
src/cleed++/RFactor/RFactorArgs.cc
src/cleed++/Search/Search.hh
src/cleed++/Search/Search.cc
src/cleed++/Search/SearchAtom.hh
src/cleed++/Search/SearchAtom.cc
src/cleed++/Pattern/Pattern.hh
src/cleed++/Model.hh
src/cleed++/BulkModel.hh
src/cleed++/AoIRFactor.h
Add small C++ utilities and IDE/qmake metadata around the cleed++ tree.
  • Introduce simple tee/stream-redirect helper types for logging C++ stream output to multiple destinations.
  • Add qmake .pro/.pri files and Eclipse CDT project/setting files to support alternative build environments for cleed++ (currently not wired into CMake).
  • Add a local .gitignore for the cleed++ directory and an empty RFAC_SRCS placeholder include file.
src/cleed++/Util/teebuf.hh
src/cleed++/Util/teestream.hh
src/cleed++/Util/teestream.cc
src/cleed++/Util/streamredirecter.hh
src/cleed++/cleed++.pro
src/cleed++/core.pri
src/cleed++/LEED/leed.pri
src/cleed++/RFactor/rfactor.pri
src/cleed++/Search/search.pri
src/cleed++/rfac.pri
src/cleed++/.project
src/cleed++/.cproject
src/cleed++/.gitignore
src/cleed++/.settings/language.settings.xml
src/cleed++/.settings/org.eclipse.cdt.managedbuilder.core.prefs
Document the experimental C++ bindings in Sphinx documentation.
  • Add a dedicated cpp_bindings documentation page describing the experimental C++ API and how to enable BUILD_CPP_BINDINGS.
  • Hook the new page into the Sphinx toctree from the main documentation index if applicable (exact index.rst changes are not fully shown in the diff).
doc/cpp_bindings.rst
doc/index.rst

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@Liam-Deacon
Copy link
Owner Author

Clarifications for #48:

  • Should I keep the qmake/Eclipse metadata from develop (*.pri, .pro, .project, .cproject, .settings), or drop them and keep only CMake sources?
  • Do you want C headers installed as part of the public ABI (e.g., include/cleed), or should cleed++ remain source-tree only for now?
  • Is the C API facade in scope for this PR, or should it be a follow-up once the C++ wrappers are validated?

@codacy-production
Copy link

codacy-production bot commented Dec 24, 2025

Codacy's Analysis Summary

100 new issues (≤ 0 issue)
1 new security issue
846 complexity
41 duplications

Review Pull Request in Codacy →

AI Reviewer available: add the codacy-review label to get contextual insights without leaving GitHub.

@Liam-Deacon Liam-Deacon marked this pull request as ready for review January 10, 2026 07:38
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @Liam-Deacon, your pull request is larger than the review limit of 150000 diff characters

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
48 Security Hotspots
3.3% Duplication on New Code (required ≤ 3%)
E Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant