.. _program_listing_file_src_array_latvec.hpp: Program Listing for File array_latvec.hpp ========================================= |exhale_lsh| :ref:`Return to documentation for file ` (``src/array_latvec.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp /* This file is part of brille. Copyright © 2019,2020 Greg Tucker brille is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. brille is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with brille. If not, see . */ #ifndef BRILLE_LATVEC_CLASS_H_ #define BRILLE_LATVEC_CLASS_H_ #include // for std::bad_cast #include #include "lattice.hpp" #include "array2.hpp" template using bArray = brille::Array2; namespace brille { class LatVec{}; template class LDVec; template class LQVec; template struct ArrayTraits{ static constexpr bool array = false; static constexpr bool latvec = false; }; #ifndef DOXYGEN_SHOULD_SKIP_THIS template struct ArrayTraits>{ static constexpr bool array = true; static constexpr bool latvec = false; }; template struct ArrayTraits>{ static constexpr bool array = true; static constexpr bool latvec = true; }; template struct ArrayTraits>{ static constexpr bool array = true; static constexpr bool latvec = true; }; #endif template class A> inline constexpr bool isArray = ArrayTraits>::array; template class A> inline constexpr bool isLatVec = ArrayTraits>::latvec; template class A> inline constexpr bool isBareArray = isArray && !isLatVec; template class A, class R, template class B> inline constexpr bool bothArrays = isArray && isArray; template class A, class R, template class B> inline constexpr bool bareArrays = isBareArray && isBareArray; template class A, class R, template class B> inline constexpr bool bothLatVecs = isLatVec && isLatVec; template bool equal_shapes(const std::vector& a, const std::vector&b){ bool ok = a.size() == b.size(); if (ok) ok = std::equal(a.begin(), a.end(), b.begin()); return ok; } template bool equal_shapes(const std::array& a, const std::array&b){ return std::equal(a.begin(), a.end(), b.begin()); } #define LVEC_SCALAR_INPLACE_OP_DEF(L,X) \ L &\ operator X (const T& v){\ for (auto x: this->subItr()) this->_data[this->s2l_d(x)] X v;\ return *this;\ } #define LVEC_ARRAY_INPLACE_OP_DEF(L,X) \ template class A>\ std::enable_if_t, L >&\ operator X (const A& b){\ auto itr = this->broadcastItr(b.shape());\ if (!equal_shapes(itr.shape(), this->shape())) throw std::runtime_error("Incompatible shaped Array for binary operation");\ for (auto [ox, ax, bx]: itr) this->_data[this->s2l_d(ax)] X b[bx];\ return *this;\ } #define LVEC_INIT_INT(N,L,X) N(const L &lat, const X &n)\ : bArray(static_cast(n),3), lattice(lat)\ {} template class LDVec: public LatVec, public bArray{ Direct lattice; public: // default constructor for zero three-vectors: explicit LDVec(const Direct& lat=Direct()) : bArray(0,3), lattice(lat) { } LVEC_INIT_INT(LDVec,Direct,int) LVEC_INIT_INT(LDVec,Direct,long) LVEC_INIT_INT(LDVec,Direct,long long) LVEC_INIT_INT(LDVec,Direct,unsigned) LVEC_INIT_INT(LDVec,Direct,unsigned long) LVEC_INIT_INT(LDVec,Direct,unsigned long long) template LDVec(const Direct& lat, Args... args) : bArray(args...), lattice(lat) { this->check_array(); } template LDVec(const LDVec& other) : bArray(other.get_hkl()), lattice(other.get_lattice()) { } Direct get_lattice() const { return lattice; } template bool samelattice(const LDVec *vec) const { return lattice.issame(vec->get_lattice()); } template bool samelattice(const LQVec *) const { return false; } template bool starlattice(const LDVec *) const { return false; } template bool starlattice(const LQVec *vec) const { return lattice.isstar(vec->get_lattice()); } template bool samelattice(const LDVec &vec) const { return lattice.issame(vec.get_lattice()); } template bool samelattice(const LQVec &) const { return false; } template bool starlattice(const LDVec &) const { return false; } template bool starlattice(const LQVec &vec) const { return lattice.isstar(vec.get_lattice()); } // extract overloads preserving lattice information template LDVec view(A... args) const; template LDVec extract(A... args) const; bArray get_hkl() const; bArray get_xyz() const; LQVec star() const; double dot(const size_t i, const size_t j) const; double norm(const size_t i) const { return sqrt(this->dot(i,i)); } LDVec cross(const size_t i, const size_t j) const; // LDVec& operator-=(const LDVec& av); // LDVec& operator+=(const LDVec& av); LVEC_SCALAR_INPLACE_OP_DEF(LDVec,+=) LVEC_SCALAR_INPLACE_OP_DEF(LDVec,-=) LVEC_SCALAR_INPLACE_OP_DEF(LDVec,*=) LVEC_SCALAR_INPLACE_OP_DEF(LDVec,/=) LVEC_ARRAY_INPLACE_OP_DEF(LDVec,+=) LVEC_ARRAY_INPLACE_OP_DEF(LDVec,-=) LVEC_ARRAY_INPLACE_OP_DEF(LDVec,*=) LVEC_ARRAY_INPLACE_OP_DEF(LDVec,/=) template void binary_operation_check(const LDVec& b) const{ assert(this->samelattice(b)); } template void binary_operation_check(const LQVec& b) const{ assert(this->starlattice(b)); } template class A, typename=typename std::enable_if>::value>::type> void binary_operation_check(const A&) const {} template bool is(const LDVec& that){ return (this->samelattice(that) && this->bArray::is(that)); } LDVec round() const { return LDVec(this->lattice, this->bArray::round()); } LDVec floor() const { return LDVec(this->lattice, this->bArray::floor()); } LDVec ceil() const { return LDVec(this->lattice, this->bArray::ceil()); } LDVec decouple() { return LDVec(lattice, this->bArray::decouple()); } protected: void check_array(); }; template class LQVec: public LatVec, public bArray{ Reciprocal lattice; public: // default constructor for zero three-vectors: explicit LQVec(const Reciprocal& lat=Reciprocal()) : bArray(0,3), lattice(lat) { } LVEC_INIT_INT(LQVec,Reciprocal,int) LVEC_INIT_INT(LQVec,Reciprocal,long) LVEC_INIT_INT(LQVec,Reciprocal,long long) LVEC_INIT_INT(LQVec,Reciprocal,unsigned) LVEC_INIT_INT(LQVec,Reciprocal,unsigned long) LVEC_INIT_INT(LQVec,Reciprocal,unsigned long long) template LQVec(const Reciprocal& lat, Args... args) : bArray(args...), lattice(lat) { this->check_array(); } template LQVec(const LQVec& other) : bArray(other.get_hkl()), lattice(other.get_lattice()) { } // LQVec(const LQVec& other, const bool m, const bool d): bArray(other.get_hkl(), m, d), lattice{other.get_lattice()} {} // LQVec(const LQVec& other, const bool m=false, const bool d=false): bArray(other.get_hkl(),m,d), lattice(other.get_lattice()) {} // //! Type conversion assignment: // template LQVec& operator=(const LQVec& other){ // this->lattice = other.get_lattice(); // *this = bArray(other.get_hkl()); // return *this; // } // LQVec& operator=(const LQVec& other){ // if (this != &other){ // do nothing if called by, e.g., a = a; // this->lattice = other.get_lattice(); // this->bArray::operator=(other); // } // return *this; // } // LQVec& operator=(LQVec&& other) noexcept { // // } Reciprocal get_lattice() const { return lattice; } template bool samelattice(const LQVec *vec) const { return lattice.issame(vec->get_lattice()); } template bool samelattice(const LDVec *) const { return false; } template bool starlattice(const LQVec *) const { return false; } template bool starlattice(const LDVec *vec) const { return lattice.isstar(vec->get_lattice()); } template bool samelattice(const LQVec &vec) const { return lattice.issame(vec.get_lattice()); } template bool samelattice(const LDVec &) const { return false; } template bool starlattice(const LQVec &) const { return false; } template bool starlattice(const LDVec &vec) const { return lattice.isstar(vec.get_lattice()); } // extract overloads preserving lattice information template LQVec view(A... args) const; template LQVec extract(A... args) const; bArray get_hkl() const; bArray get_xyz() const; LDVec star() const; double dot(const size_t i, const size_t j) const; double norm(const size_t i) const { return sqrt(this->dot(i,i)); } LQVec cross(const size_t i, const size_t j) const; LVEC_SCALAR_INPLACE_OP_DEF(LQVec,+=) LVEC_SCALAR_INPLACE_OP_DEF(LQVec,-=) LVEC_SCALAR_INPLACE_OP_DEF(LQVec,*=) LVEC_SCALAR_INPLACE_OP_DEF(LQVec,/=) LVEC_ARRAY_INPLACE_OP_DEF(LQVec,+=) LVEC_ARRAY_INPLACE_OP_DEF(LQVec,-=) LVEC_ARRAY_INPLACE_OP_DEF(LQVec,*=) LVEC_ARRAY_INPLACE_OP_DEF(LQVec,/=) // LQVec operator -(); template void binary_operation_check(const LQVec& b) const{ assert(this->samelattice(b)); } template void binary_operation_check(const LDVec& b) const{ assert(this->starlattice(b)); } template class A, typename=typename std::enable_if>::value>::type> void binary_operation_check(const A&) const {} template bool is(const LQVec& that) const { return (this->samelattice(that) && this->bArray::is(that)); } LQVec round() const { return LQVec(this->lattice, this->bArray::round()); } LQVec floor() const { return LQVec(this->lattice, this->bArray::floor()); } LQVec ceil() const { return LQVec(this->lattice, this->bArray::ceil()); } // static LQVec from_invA(const Reciprocal& lat, const bArray& vec, const int=1){ assert(vec.is_row_ordered() && vec.is_contiguous() && vec.size(vec.ndim()-1)==3); // initialise an empy array for the relative lattice unit components bArray rlu(vec.shape(), vec.stride()); auto vsh = vec.shape(); vsh.back() = 0; // grab the transformation matric from the lattice std::vector fromxyz = lat.get_inverse_xyz_transform(); for (auto i: vec.subItr(vsh)) brille::utils::multiply_matrix_vector(rlu.ptr(i), fromxyz.data(), vec.ptr(i)); // finally make the vector(s) with lattice and components: return LQVec(lat, rlu); } LQVec decouple() { return LQVec(lattice, this->bArray::decouple()); } protected: void check_array(); }; #undef LVEC_SCALAR_INPLACE_OP_DEF #undef LVEC_ARRAY_INPLACE_OP_DEF #undef LVEC_INIT_INT #ifndef DOXYGEN_SHOULD_SKIP_THIS // extend the lattice traits structs template struct LatticeTraits>{ using type = Direct; using star = Reciprocal; }; template struct LatticeTraits>{ using type = Reciprocal; using star = Direct; }; #endif template struct LatVecTraits{ using type = void; //< LDVec or LQVec using star = void; //< LQVec or LDVec }; #ifndef DOXYGEN_SHOULD_SKIP_THIS template struct LatVecTraits,S>{ using type = LDVec; using star = LQVec; }; template struct LatVecTraits,S>{ using type = LQVec; using star = LDVec; }; template struct LatVecTraits{ using type = LDVec; using star = LQVec; }; template struct LatVecTraits{ using type = LQVec; using star = LDVec; }; #endif template using LatVecType = typename LatVecTraits::type; template using LatVecStar = typename LatVecTraits::star; #include "array_latvec.tpp" #include "array_ldvec.tpp" #include "array_lqvec.tpp" } #endif