From a9e7744b7ac674e02670d1f47078eb65271c395d Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 23 Jun 2021 11:10:43 -0400 Subject: [PATCH 01/79] Start converting GridBin class from abstract base class to full implementation; which calc routine gets used will depend on if the grid is X-aligned and orthogonal or not. --- src/GridBin.h | 151 +++++++++++++------------------------------------- 1 file changed, 40 insertions(+), 111 deletions(-) diff --git a/src/GridBin.h b/src/GridBin.h index 0136a86265..91431eaf7b 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -1,14 +1,17 @@ #ifndef INC_GRIDBIN_H #define INC_GRIDBIN_H -#include "Matrix_3x3.h" #include "Box.h" /// Class used to perform binning on/get voxel coords of 3D grids. class GridBin { public: - GridBin() : OXYZ_(0.0) {} - virtual ~GridBin() {} + /// CONSTRUCTOR + GridBin() : OXYZ_(0.0), + dx_(-1.0), dy_(-1.0), dz_(-1.0), mx_(0), my_(0), mz_(0), + nx_(0), ny_(0), nz_(0), voxelvolume_(0) + {} /// \return true if given coordinates are on grid; set corresponding bin indices. - virtual bool Calc(double, double, double, size_t&, size_t&, size_t&) const = 0; + bool Calc(double, double, double, size_t&, size_t&, size_t&) const; + /// Given coordinates, set corresponding bin indices; no bounds check. virtual void Indices(double, double, double, long int&, long int&, long int&) const = 0; /// \return coordinates of bin for given indices; no bound check. @@ -26,119 +29,45 @@ class GridBin { /// \return Grid origin. Vec3 const& GridOrigin() const { return OXYZ_; } protected: - Vec3 OXYZ_; ///< Grid origin. + Vec3 OXYZ_; ///< Grid origin. + double dx_, dy_, dz_; ///< Grid spacing (Ang., Cartesian, orthogonal). + double mx_, my_, mz_; ///< Grid max (Ang., Cartesian, orthogonal). + double nx_, ny_, nz_; ///< Number of bins in double precision (nonortho). + double voxelvolume_; ///< Volume of a single voxel (Ang^3). + Box box_; ///< Contain grid unit cell vectors, frac. vectors, volume. }; // ----------------------------------------------------------------------------- -/// Orthogonal grid -class GridBin_Ortho : public GridBin { - public: - GridBin_Ortho() : dx_(-1.0), dy_(-1.0), dz_(-1.0), mx_(0), my_(0), mz_(0) {} - GridBin* Copy() const { return (GridBin*)(new GridBin_Ortho(*this)); } - bool Calc(double x, double y, double z, - size_t& i, size_t& j, size_t& k) const - { - if (x >= OXYZ_[0] && x < mx_) { // X - if (y >= OXYZ_[1] && y < my_) { // Y - if (z >= OXYZ_[2] && z < mz_) { // Z - i = (size_t)((x-OXYZ_[0]) / dx_); - j = (size_t)((y-OXYZ_[1]) / dy_); - k = (size_t)((z-OXYZ_[2]) / dz_); - return true; - } + +/** \return true if given coordinates are on grid; set corresponding bin indices. */ +bool GridBin::Calc(double x, double y, double z, size_t& i, size_t& j, size_t& k) const +{ + if (box_.Is_X_Aligned_Ortho()) { + // X-aligned and orthogonal + if (x >= OXYZ_[0] && x < mx_) { // X + if (y >= OXYZ_[1] && y < my_) { // Y + if (z >= OXYZ_[2] && z < mz_) { // Z + i = (size_t)((x-OXYZ_[0]) / dx_); + j = (size_t)((y-OXYZ_[1]) / dy_); + k = (size_t)((z-OXYZ_[2]) / dz_); + return true; } } - return false; - } - void Indices(double x, double y, double z, long int& i, long int& j, long int& k) const { - i = (long int)((x-OXYZ_[0]) / dx_); - j = (long int)((y-OXYZ_[1]) / dy_); - k = (long int)((z-OXYZ_[2]) / dz_); - } - Vec3 Corner(long int i, long int j, long int k) const { - return Vec3((double)i*dx_+OXYZ_[0], - (double)j*dy_+OXYZ_[1], - (double)k*dz_+OXYZ_[2]); - } - Vec3 Center(long int i, long int j, long int k) const { - return Vec3((double)i*dx_+OXYZ_[0]+0.5*dx_, - (double)j*dy_+OXYZ_[1]+0.5*dy_, - (double)k*dz_+OXYZ_[2]+0.5*dz_); } - Matrix_3x3 Ucell() const { return Matrix_3x3(mx_-OXYZ_[0], my_-OXYZ_[1], mz_-OXYZ_[2]); } - bool IsOrthoGrid() const { return true; } - double VoxelVolume() const { return dx_ * dy_ * dz_; } - /// Setup with given origin, spacing; calculate maximum. - void Setup_O_D(size_t nx, size_t ny, size_t nz, - Vec3 const& oxyzIn, Vec3 const& dxyz) - { - OXYZ_ = oxyzIn; - dx_ = dxyz[0]; dy_ = dxyz[1]; dz_ = dxyz[2]; - mx_ = OXYZ_[0] + ((double)nx * dx_); - my_ = OXYZ_[1] + ((double)ny * dy_); - mz_ = OXYZ_[2] + ((double)nz * dz_); - } - double DX() const { return dx_; } - double DY() const { return dy_; } - double DZ() const { return dz_; } - private: - double dx_, dy_, dz_; ///< Grid spacing - double mx_, my_, mz_; ///< Grid max -}; -// ----------------------------------------------------------------------------- -/// Non-orthogonal grid. -class GridBin_Nonortho : public GridBin { - public: - GridBin_Nonortho() {} - GridBin* Copy() const { return (GridBin*)(new GridBin_Nonortho(*this)); } - bool Calc(double x, double y, double z, - size_t& i, size_t& j, size_t& k) const - { - Vec3 frac = recip_ * Vec3(x - OXYZ_[0], y - OXYZ_[1], z - OXYZ_[2]); - if (frac[0] >= 0.0 && frac[0] < 1.0) { - if (frac[1] >= 0.0 && frac[1] < 1.0) { - if (frac[2] >= 0.0 && frac[2] < 1.0) { - i = (size_t)(frac[0] * nx_); - j = (size_t)(frac[1] * ny_); - k = (size_t)(frac[2] * nz_); - return true; - } + } else { + // Not X-aligned or non-orthogonal + Vec3 frac = box_.FracCell() * Vec3(x - OXYZ_[0], y - OXYZ_[1], z - OXYZ_[2]); + if (frac[0] >= 0.0 && frac[0] < 1.0) { + if (frac[1] >= 0.0 && frac[1] < 1.0) { + if (frac[2] >= 0.0 && frac[2] < 1.0) { + i = (size_t)(frac[0] * nx_); + j = (size_t)(frac[1] * ny_); + k = (size_t)(frac[2] * nz_); + return true; } } - return false; - } - void Indices(double x, double y, double z, long int& i, long int& j, long int& k) const { - Vec3 frac = recip_ * Vec3(x - OXYZ_[0], y - OXYZ_[1], z - OXYZ_[2]); - i = (long int)(frac[0] * nx_); - j = (long int)(frac[1] * ny_); - k = (long int)(frac[2] * nz_); - } - Vec3 Corner(long int i, long int j, long int k) const { - Vec3 frac( (double)i / nx_, (double)j / ny_, (double)k / nz_ ); - return ucell_.TransposeMult( frac ) + OXYZ_; } - Vec3 Center(long int i, long int j, long int k) const { - Vec3 frac_half((1.0 + 2.0 * (double)i) / (2.0 * nx_), //(0.5 * (1.0 / nx_)) + ((double)i / nx_), - (1.0 + 2.0 * (double)j) / (2.0 * ny_), - (1.0 + 2.0 * (double)k) / (2.0 * nz_)); - return ucell_.TransposeMult( frac_half ) + OXYZ_; - } - Matrix_3x3 Ucell() const { return ucell_; } - bool IsOrthoGrid() const { return false; } - double VoxelVolume() const { return voxelvolume_; } - /// Setup with given bins, origin and box coordinates. - void Setup_O_Box(size_t nxIn, size_t nyIn, size_t nzIn, - Vec3 const& oxyzIn, Box const& boxIn) { - nx_ = (double)nxIn; ny_ = (double)nyIn; nz_ = (double)nzIn; - OXYZ_ = oxyzIn; - // Get unit cell and fractional cell vectors (recip). - ucell_ = boxIn.UnitCell(); - recip_ = boxIn.FracCell(); - voxelvolume_ = boxIn.CellVolume() / (nx_ * ny_ * nz_); - } - private: - double nx_, ny_, nz_; ///< Number of bins in double precision. - double voxelvolume_; ///< Voxel volume. - Matrix_3x3 ucell_; ///< Unit cell axes coordinates. - Matrix_3x3 recip_; ///< Fractional axes coordinates. -}; + } + return false; +} + #endif From c3d4c68d50b020e441722dec4e881badb854e4b0 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 23 Jun 2021 11:18:30 -0400 Subject: [PATCH 02/79] Implement GridBin Indices, Center, and Corner --- src/GridBin.h | 58 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/src/GridBin.h b/src/GridBin.h index 91431eaf7b..16ad5c77be 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -11,13 +11,13 @@ class GridBin { {} /// \return true if given coordinates are on grid; set corresponding bin indices. bool Calc(double, double, double, size_t&, size_t&, size_t&) const; - /// Given coordinates, set corresponding bin indices; no bounds check. - virtual void Indices(double, double, double, long int&, long int&, long int&) const = 0; + void Indices(double, double, double, long int&, long int&, long int&) const; /// \return coordinates of bin for given indices; no bound check. - virtual Vec3 Corner(long int, long int, long int) const = 0; + Vec3 Corner(long int, long int, long int) const; /// \return coordinates of bin center for given indices; no bounds check. - virtual Vec3 Center(long int, long int, long int) const = 0; + Vec3 Center(long int, long int, long int) const; + /// \return unit cell matrix. // TODO: Make const&? virtual Matrix_3x3 Ucell() const = 0; /// \return true if GridBin type is orthogonal. @@ -70,4 +70,54 @@ bool GridBin::Calc(double x, double y, double z, size_t& i, size_t& j, size_t& k return false; } +/** Given coordinates, set corresponding bin indices; no bounds check. */ +void GridBin::Indices(double x, double y, double z, long int& i, long int& j, long int& k) const +{ + if (box_.Is_X_Aligned_Ortho()) { + // X-aligned and orthogonal + i = (long int)((x-OXYZ_[0]) / dx_); + j = (long int)((y-OXYZ_[1]) / dy_); + k = (long int)((z-OXYZ_[2]) / dz_); + } else { + // Not X-aligned or non-orthogonal + Vec3 frac = box_.FracCell() * Vec3(x - OXYZ_[0], y - OXYZ_[1], z - OXYZ_[2]); + i = (long int)(frac[0] * nx_); + j = (long int)(frac[1] * ny_); + k = (long int)(frac[2] * nz_); + } +} + + +/** \return coordinates of bin for given indices; no bound check. */ +Vec3 GridBin::Corner(long int i, long int j, long int k) const +{ + if (box_.Is_X_Aligned_Ortho()) { + // X-aligned and orthogonal + return Vec3((double)i*dx_+OXYZ_[0], + (double)j*dy_+OXYZ_[1], + (double)k*dz_+OXYZ_[2]); + } else { + // Not X-aligned or non-orthogonal + Vec3 frac( (double)i / nx_, (double)j / ny_, (double)k / nz_ ); + return box_.UnitCell().TransposeMult( frac ) + OXYZ_; + } +} + +/** \return coordinates of bin center for given indices; no bounds check. */ +Vec3 GridBin::Center(long int i, long int j, long int k) const +{ + if (box_.Is_X_Aligned_Ortho()) { + // X-aligned and orthogonal + return Vec3((double)i*dx_+OXYZ_[0]+0.5*dx_, + (double)j*dy_+OXYZ_[1]+0.5*dy_, + (double)k*dz_+OXYZ_[2]+0.5*dz_); + } else { + // Not X-aligned or non-orthogonal + Vec3 frac_half((1.0 + 2.0 * (double)i) / (2.0 * nx_), //(0.5 * (1.0 / nx_)) + ((double)i / nx_), + (1.0 + 2.0 * (double)j) / (2.0 * ny_), + (1.0 + 2.0 * (double)k) / (2.0 * nz_)); + return box_.UnitCell().TransposeMult( frac_half ) + OXYZ_; + } +} + #endif From 2eba0cfebf35eae98168e65fff5d174ebfd43405 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 23 Jun 2021 11:24:20 -0400 Subject: [PATCH 03/79] Finish initial conversion of GridBin --- src/GridBin.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/GridBin.h b/src/GridBin.h index 16ad5c77be..f7117054ee 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -17,15 +17,14 @@ class GridBin { Vec3 Corner(long int, long int, long int) const; /// \return coordinates of bin center for given indices; no bounds check. Vec3 Center(long int, long int, long int) const; - - /// \return unit cell matrix. // TODO: Make const&? - virtual Matrix_3x3 Ucell() const = 0; - /// \return true if GridBin type is orthogonal. - virtual bool IsOrthoGrid() const = 0; + /// \return unit cell matrix. + Matrix_3x3 const& Ucell() const { return box_.UnitCell(); } + /// \return true if Grid is X-aligned and orthogonal. + bool IsOrthoGrid() const { return box_.Is_X_Aligned_Ortho(); } /// \return Voxel volume. - virtual double VoxelVolume() const = 0; + double VoxelVolume() const { return voxelvolume_; } /// \return a copy of this GridBin. - virtual GridBin* Copy() const = 0; + //virtual GridBin* Copy() const = 0; /// \return Grid origin. Vec3 const& GridOrigin() const { return OXYZ_; } protected: From aba1787e2470c56e06fb849da9b931cc4ff9b737 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 23 Jun 2021 11:32:20 -0400 Subject: [PATCH 04/79] Add orthogonal setup routine. --- src/GridBin.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/GridBin.h b/src/GridBin.h index f7117054ee..4b99ef902a 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -27,6 +27,10 @@ class GridBin { //virtual GridBin* Copy() const = 0; /// \return Grid origin. Vec3 const& GridOrigin() const { return OXYZ_; } + + // Set up routines. + /// Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. + void Setup_O_D(size_t, size_t, size_t, Vec3 const&, Vec3 const&); protected: Vec3 OXYZ_; ///< Grid origin. double dx_, dy_, dz_; ///< Grid spacing (Ang., Cartesian, orthogonal). @@ -119,4 +123,36 @@ Vec3 GridBin::Center(long int i, long int j, long int k) const } } +/** Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. */ +void GridBin::Setup_O_D(size_t nx, size_t ny, size_t nz, + Vec3 const& oxyzIn, Vec3 const& dxyz) +{ + OXYZ_ = oxyzIn; + dx_ = dxyz[0]; + dy_ = dxyz[1]; + dz_ = dxyz[2]; + mx_ = OXYZ_[0] + ((double)nx * dx_); + my_ = OXYZ_[1] + ((double)ny * dy_); + mz_ = OXYZ_[2] + ((double)nz * dz_); + nx_ = (double)nx; + ny_ = (double)ny; + nz_ = (double)nz; + voxelvolume_ = dx_ * dy_ * dz_; + // Set orthogonal unit cell vectors. TODO should these be w.r.t. the offset? + double ucell[9]; + ucell[0] = (double)nx * dx_; + ucell[1] = 0; + ucell[2] = 0; + + ucell[3] = 0; + ucell[4] = (double)ny * dy_; + ucell[5] = 0; + + ucell[6] = 0; + ucell[7] = 0; + ucell[8] = (double)nz * dz_; + + box_.SetupFromUcell(ucell); + box_.PrintDebug("GridBin::Setup_O_D"); +} #endif From 7b891a09bc8ce26395bb4ad3ce11cf9364fced67 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 23 Jun 2021 11:40:59 -0400 Subject: [PATCH 05/79] Add setup from origin and box --- src/GridBin.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/GridBin.h b/src/GridBin.h index 4b99ef902a..5d269572f6 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -1,5 +1,6 @@ #ifndef INC_GRIDBIN_H #define INC_GRIDBIN_H +#include // size_t #include "Box.h" /// Class used to perform binning on/get voxel coords of 3D grids. class GridBin { @@ -31,6 +32,8 @@ class GridBin { // Set up routines. /// Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. void Setup_O_D(size_t, size_t, size_t, Vec3 const&, Vec3 const&); + /// Set up for grid with given bins, origin, and box. + void Setup_O_Box(size_t, size_t, size_t, Vec3 const&, Box const&); protected: Vec3 OXYZ_; ///< Grid origin. double dx_, dy_, dz_; ///< Grid spacing (Ang., Cartesian, orthogonal). @@ -155,4 +158,31 @@ void GridBin::Setup_O_D(size_t nx, size_t ny, size_t nz, box_.SetupFromUcell(ucell); box_.PrintDebug("GridBin::Setup_O_D"); } + + +/** Set up for grid with given bins, origin, and box.*/ +void GridBin::Setup_O_Box(size_t nxIn, size_t nyIn, size_t nzIn, + Vec3 const& oxyzIn, Box const& boxIn) +{ + nx_ = (double)nxIn; + ny_ = (double)nyIn; + nz_ = (double)nzIn; + OXYZ_ = oxyzIn; + box_ = boxIn; + // Get the 3 individual unit cell vector lengths + double l_Avec = box_.UnitCell().Row1().Length(); + double l_Bvec = box_.UnitCell().Row2().Length(); + double l_Cvec = box_.UnitCell().Row3().Length(); + // Get spacing from vector length over bins + dx_ = l_Avec / nx_; + dy_ = l_Bvec / ny_; + dz_ = l_Cvec / nz_; + // Get max from origin plus vector length + mx_ = OXYZ_[0] + l_Avec; + my_ = OXYZ_[1] + l_Bvec; + mz_ = OXYZ_[2] + l_Cvec; + // Get voxel volume from total grid volume over number of bins. + voxelvolume_ = boxIn.CellVolume() / (nx_ * ny_ * nz_); +} + #endif From 06b85dea842063750526cd5cec05092b67ea75d1 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 23 Jun 2021 11:51:47 -0400 Subject: [PATCH 06/79] Modify DataSet_3D to use new GridBin --- src/DataSet_3D.cpp | 56 +++++++++++++++++++++------------------------- src/DataSet_3D.h | 12 ++++++---- src/GridBin.h | 11 +++++++-- 3 files changed, 42 insertions(+), 37 deletions(-) diff --git a/src/DataSet_3D.cpp b/src/DataSet_3D.cpp index a8b425e69d..1f791bec55 100644 --- a/src/DataSet_3D.cpp +++ b/src/DataSet_3D.cpp @@ -2,21 +2,24 @@ #include "DataSet_3D.h" #include "CpptrajStdio.h" -// DESTRUCTOR -DataSet_3D::~DataSet_3D() { if (gridBin_ != 0) delete gridBin_; } +/** CONSTRUCTOR */ +DataSet_3D::DataSet_3D() {} -// COPY CONSTRUCTOR -DataSet_3D::DataSet_3D(DataSet_3D const& rhs) : DataSet(rhs), gridBin_(0) { - if (rhs.gridBin_ != 0) gridBin_ = rhs.gridBin_->Copy(); -} +/** DESTRUCTOR */ +DataSet_3D::~DataSet_3D() {} + +/** COPY CONSTRUCTOR */ +DataSet_3D::DataSet_3D(DataSet_3D const& rhs) : + DataSet(rhs), + gridBin_(rhs.gridBin_) +{} -// ASSIGNMENT -DataSet_3D& DataSet_3D::operator=(DataSet_3D const& rhs) { +/** ASSIGNMENT */ +DataSet_3D& DataSet_3D::operator=(DataSet_3D const& rhs) +{ if (this == &rhs) return *this; DataSet::operator=(rhs); - if (gridBin_ != 0) delete gridBin_; - gridBin_ = 0; - if (rhs.gridBin_ != 0) gridBin_ = rhs.gridBin_->Copy(); + gridBin_ = rhs.gridBin_; return *this; } @@ -28,11 +31,8 @@ int DataSet_3D::Allocate_N_O_Box(size_t nx, size_t ny, size_t nz, mprinterr("Error: One or more grid sizes are 0: %zu %zu %zu\n", nx, ny, nz); return 1; } - if (gridBin_ != 0) delete gridBin_; - GridBin_Nonortho* gb = new GridBin_Nonortho(); // Set origin and unit cell params. - gb->Setup_O_Box(nx, ny, nz, oxyz, boxIn); - gridBin_ = (GridBin*)gb; + gridBin_.Setup_O_Box(nx, ny, nz, oxyz, boxIn); return Allocate3D(nx, ny, nz); } @@ -44,11 +44,8 @@ int DataSet_3D::Allocate_N_O_D(size_t nx, size_t ny, size_t nz, mprinterr("Error: One or more grid sizes are 0: %zu %zu %zu\n", nx, ny, nz); return 1; } - if (gridBin_ != 0) delete gridBin_; - GridBin_Ortho* gb = new GridBin_Ortho(); // Set origin and spacing, calculate maximum (for binning). - gb->Setup_O_D(nx, ny, nz, oxyz, dxyz); - gridBin_ = (GridBin*)gb; + gridBin_.Setup_O_D(nx, ny, nz, oxyz, dxyz); return Allocate3D(nx, ny, nz); } @@ -88,24 +85,21 @@ int DataSet_3D::Allocate_X_C_D(Vec3 const& sizes, Vec3 const& center, Vec3 const // DataSet_3D::GridInfo() void DataSet_3D::GridInfo() const { - if (gridBin_ == 0) return; - Vec3 const& oxyz = gridBin_->GridOrigin(); + Vec3 const& oxyz = gridBin_.GridOrigin(); mprintf("\t\t-=Grid Dims=- %8s %8s %8s\n", "X", "Y", "Z"); mprintf("\t\t Bins: %8zu %8zu %8zu\n", NX(), NY(), NZ()); mprintf("\t\t Origin: %8g %8g %8g\n", oxyz[0], oxyz[1], oxyz[2]); - if (gridBin_->IsOrthoGrid()) { - GridBin_Ortho const& gb = static_cast( *gridBin_ ); - mprintf("\t\t Spacing: %8g %8g %8g\n", gb.DX(), gb.DY(), gb.DZ()); + //if (gridBin_.IsOrthoGrid()) { + mprintf("\t\t Spacing: %8g %8g %8g\n", gridBin_.DX(), gridBin_.DY(), gridBin_.DZ()); mprintf("\t\t Center: %8g %8g %8g\n", - oxyz[0] + (NX()/2)*gb.DX(), - oxyz[1] + (NY()/2)*gb.DY(), - oxyz[2] + (NZ()/2)*gb.DZ()); + oxyz[0] + (NX()/2)*gridBin_.DX(), + oxyz[1] + (NY()/2)*gridBin_.DY(), + oxyz[2] + (NZ()/2)*gridBin_.DZ()); //mprintf("\tGrid max : %8.3f %8.3f %8.3f\n", grid.MX(), grid.MY(), grid.MZ()); - } else { - Box box; - box.SetupFromUcell(gridBin_->Ucell()); + //} else { + Box const& box = gridBin_.GridBox(); mprintf("\t\tBox: %s ABC={%g %g %g} abg={%g %g %g}\n", box.CellShapeName(), box.Param(Box::X), box.Param(Box::Y), box.Param(Box::Z), box.Param(Box::ALPHA), box.Param(Box::BETA), box.Param(Box::GAMMA)); - } + //} } diff --git a/src/DataSet_3D.h b/src/DataSet_3D.h index e280f9a89f..15b5647457 100644 --- a/src/DataSet_3D.h +++ b/src/DataSet_3D.h @@ -7,12 +7,16 @@ class Box; // TODO: Use DataSet Dims? class DataSet_3D : public DataSet { public: - DataSet_3D() : gridBin_(0) {} + /// CONSTRUCTOR + DataSet_3D(); virtual ~DataSet_3D(); // Virtual since this class is inherited. + /// COPY CONSTRUCTOR DataSet_3D(DataSet_3D const&); + /// ASSIGNMENT DataSet_3D& operator=(DataSet_3D const&); + /// CONSTRUCTOR - type, format DataSet_3D(DataSet::DataType tIn, TextFormat const& fIn) : - DataSet(tIn, GRID_3D, fIn, 3), gridBin_(0) {} + DataSet(tIn, GRID_3D, fIn, 3) {} // TODO enable append? int Append(DataSet*) { return 1; } int Allocate(SizeArray const&) { return 1; } // TODO enable? @@ -61,7 +65,7 @@ class DataSet_3D : public DataSet { /// Print grid info. void GridInfo() const; // ------------------------------------------- - GridBin const& Bin() const { return *gridBin_; } + GridBin const& Bin() const { return gridBin_; } private: /// Check if grid dimension is even; if not, increment it by 1. static void CheckEven(size_t&, char); @@ -69,6 +73,6 @@ class DataSet_3D : public DataSet { // TODO: Make public if grids will be used for other than binning. virtual int Allocate3D(size_t, size_t, size_t) = 0; - GridBin* gridBin_; ///< Used to calculate bins/coords depending on grid type. + GridBin gridBin_; ///< Used to calculate bins/coords depending on grid type. }; #endif diff --git a/src/GridBin.h b/src/GridBin.h index 5d269572f6..4c2f0bc1d3 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -18,9 +18,11 @@ class GridBin { Vec3 Corner(long int, long int, long int) const; /// \return coordinates of bin center for given indices; no bounds check. Vec3 Center(long int, long int, long int) const; - /// \return unit cell matrix. + /// \return Grid unit cell matrix. TODO just use GridBox? Matrix_3x3 const& Ucell() const { return box_.UnitCell(); } - /// \return true if Grid is X-aligned and orthogonal. + /// \return Grid box + Box const& GridBox() const { return box_; } + /// \return true if Grid is X-aligned and orthogonal. TODO this may not be necessary bool IsOrthoGrid() const { return box_.Is_X_Aligned_Ortho(); } /// \return Voxel volume. double VoxelVolume() const { return voxelvolume_; } @@ -29,6 +31,11 @@ class GridBin { /// \return Grid origin. Vec3 const& GridOrigin() const { return OXYZ_; } + // TODO are these spacing routines needed? + double DX() const { return dx_; } + double DY() const { return dy_; } + double DZ() const { return dz_; } + // Set up routines. /// Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. void Setup_O_D(size_t, size_t, size_t, Vec3 const&, Vec3 const&); From 16e7ba0c10284aae27de6747b2daba2d69f94fba Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 23 Jun 2021 14:00:38 -0400 Subject: [PATCH 07/79] Modify for new gridbin --- src/Action_Volmap.cpp | 2 +- src/DataIO_Std.cpp | 32 ++++++++++++++------------------ 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/Action_Volmap.cpp b/src/Action_Volmap.cpp index bb4aeb1137..52f1e567c2 100644 --- a/src/Action_Volmap.cpp +++ b/src/Action_Volmap.cpp @@ -214,7 +214,7 @@ Action::RetType Action_Volmap::Init(ArgList& actionArgs, ActionInit& init, int d mprinterr("Error: Currently only works with orthogonal grids.\n"); return Action::ERR; } - GridBin_Ortho const& gbo = static_cast( grid_->Bin() ); + GridBin const& gbo = static_cast( grid_->Bin() ); dx_ = gbo.DX(); dy_ = gbo.DY(); dz_ = gbo.DZ(); diff --git a/src/DataIO_Std.cpp b/src/DataIO_Std.cpp index 64a4d19ac9..28af10dd67 100644 --- a/src/DataIO_Std.cpp +++ b/src/DataIO_Std.cpp @@ -795,13 +795,11 @@ int DataIO_Std::Read_3D(std::string const& fname, // Assume XYZ coords are of bin corners. Need to offset coords by half // the voxel size. if (!ds->Bin().IsOrthoGrid()) { - GridBin_Nonortho const& b = static_cast( ds->Bin() ); - offset = b.Ucell().TransposeMult(Vec3( 1/(2*(double)ds->NX()), - 1/(2*(double)ds->NY()), - 1/(2*(double)ds->NZ()) )); + offset = ds->Bin().Ucell().TransposeMult(Vec3( 1/(2*(double)ds->NX()), + 1/(2*(double)ds->NY()), + 1/(2*(double)ds->NZ()) )); } else { - GridBin_Ortho const& b = static_cast( ds->Bin() ); - offset = Vec3(b.DX()/2, b.DY()/2, b.DZ()/2); + offset = Vec3(ds->Bin().DX()/2, ds->Bin().DY()/2, ds->Bin().DZ()/2); } } if (debug_ > 0) @@ -1456,20 +1454,18 @@ int DataIO_Std::WriteSet3D( DataSet const& setIn, CpptrajFile& file ) { set.Bin().GridOrigin()[1], set.Bin().GridOrigin()[2]); if (set.Bin().IsOrthoGrid()) { - GridBin_Ortho const& b = static_cast( set.Bin() ); - file.Printf("#delta %12.7f %12.7f %12.7f\n", b.DX(), b.DY(), b.DZ()); + file.Printf("#delta %12.7f %12.7f %12.7f\n", set.Bin().DX(), set.Bin().DY(), set.Bin().DZ()); } else { - GridBin_Nonortho const& b = static_cast( set.Bin() ); file.Printf("#delta %12.7f %12.7f %12.7f %12.7f %12.7f %12.7f %12.7f %12.7f %12.7f\n", - b.Ucell()[0]/set.NX(), - b.Ucell()[1]/set.NX(), - b.Ucell()[2]/set.NX(), - b.Ucell()[3]/set.NY(), - b.Ucell()[4]/set.NY(), - b.Ucell()[5]/set.NY(), - b.Ucell()[6]/set.NZ(), - b.Ucell()[7]/set.NZ(), - b.Ucell()[8]/set.NZ()); + set.Bin().Ucell()[0]/set.NX(), + set.Bin().Ucell()[1]/set.NX(), + set.Bin().Ucell()[2]/set.NX(), + set.Bin().Ucell()[3]/set.NY(), + set.Bin().Ucell()[4]/set.NY(), + set.Bin().Ucell()[5]/set.NY(), + set.Bin().Ucell()[6]/set.NZ(), + set.Bin().Ucell()[7]/set.NZ(), + set.Bin().Ucell()[8]/set.NZ()); } file.Printf("#%s %s %s %s\n", Xdim.Label().c_str(), Ydim.Label().c_str(), Zdim.Label().c_str(), set.legend()); From b27a65b4b50517ce650d7574ef159255ca35787b Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 23 Jun 2021 14:06:49 -0400 Subject: [PATCH 08/79] Apparently these need to be explicitly inlined --- src/GridBin.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/GridBin.h b/src/GridBin.h index 4c2f0bc1d3..0627ccff7c 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -11,36 +11,36 @@ class GridBin { nx_(0), ny_(0), nz_(0), voxelvolume_(0) {} /// \return true if given coordinates are on grid; set corresponding bin indices. - bool Calc(double, double, double, size_t&, size_t&, size_t&) const; + inline bool Calc(double, double, double, size_t&, size_t&, size_t&) const; /// Given coordinates, set corresponding bin indices; no bounds check. - void Indices(double, double, double, long int&, long int&, long int&) const; + inline void Indices(double, double, double, long int&, long int&, long int&) const; /// \return coordinates of bin for given indices; no bound check. - Vec3 Corner(long int, long int, long int) const; + inline Vec3 Corner(long int, long int, long int) const; /// \return coordinates of bin center for given indices; no bounds check. - Vec3 Center(long int, long int, long int) const; + inline Vec3 Center(long int, long int, long int) const; /// \return Grid unit cell matrix. TODO just use GridBox? - Matrix_3x3 const& Ucell() const { return box_.UnitCell(); } + inline Matrix_3x3 const& Ucell() const { return box_.UnitCell(); } /// \return Grid box - Box const& GridBox() const { return box_; } + inline Box const& GridBox() const { return box_; } /// \return true if Grid is X-aligned and orthogonal. TODO this may not be necessary - bool IsOrthoGrid() const { return box_.Is_X_Aligned_Ortho(); } + inline bool IsOrthoGrid() const { return box_.Is_X_Aligned_Ortho(); } /// \return Voxel volume. - double VoxelVolume() const { return voxelvolume_; } + inline double VoxelVolume() const { return voxelvolume_; } /// \return a copy of this GridBin. //virtual GridBin* Copy() const = 0; /// \return Grid origin. - Vec3 const& GridOrigin() const { return OXYZ_; } + inline Vec3 const& GridOrigin() const { return OXYZ_; } // TODO are these spacing routines needed? - double DX() const { return dx_; } - double DY() const { return dy_; } - double DZ() const { return dz_; } + inline double DX() const { return dx_; } + inline double DY() const { return dy_; } + inline double DZ() const { return dz_; } // Set up routines. /// Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. - void Setup_O_D(size_t, size_t, size_t, Vec3 const&, Vec3 const&); + inline void Setup_O_D(size_t, size_t, size_t, Vec3 const&, Vec3 const&); /// Set up for grid with given bins, origin, and box. - void Setup_O_Box(size_t, size_t, size_t, Vec3 const&, Box const&); + inline void Setup_O_Box(size_t, size_t, size_t, Vec3 const&, Box const&); protected: Vec3 OXYZ_; ///< Grid origin. double dx_, dy_, dz_; ///< Grid spacing (Ang., Cartesian, orthogonal). From 052783001599aa3772b9372a07517e2af7dab2ef Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 23 Jun 2021 14:45:20 -0400 Subject: [PATCH 09/79] Add debug for Setup_O_Box --- src/GridBin.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/GridBin.h b/src/GridBin.h index 0627ccff7c..bdbba9d1b9 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -176,6 +176,7 @@ void GridBin::Setup_O_Box(size_t nxIn, size_t nyIn, size_t nzIn, nz_ = (double)nzIn; OXYZ_ = oxyzIn; box_ = boxIn; + box_.PrintDebug("GridBin::Setup_O_Box"); // Get the 3 individual unit cell vector lengths double l_Avec = box_.UnitCell().Row1().Length(); double l_Bvec = box_.UnitCell().Row2().Length(); From 42ca1c1bbf4224854f2208f13e5ecad9ba5fd942 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 24 Jun 2021 10:24:05 -0400 Subject: [PATCH 10/79] Add some debug info, commented out for now. --- src/GridBin.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/GridBin.h b/src/GridBin.h index bdbba9d1b9..cef7e0a184 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -2,6 +2,7 @@ #define INC_GRIDBIN_H #include // size_t #include "Box.h" +//#inc lude "CpptrajStdio.h" // DEBUG /// Class used to perform binning on/get voxel coords of 3D grids. class GridBin { public: @@ -55,6 +56,7 @@ class GridBin { bool GridBin::Calc(double x, double y, double z, size_t& i, size_t& j, size_t& k) const { if (box_.Is_X_Aligned_Ortho()) { + //mprintf("DEBUG: X-aligned Calc\n"); // X-aligned and orthogonal if (x >= OXYZ_[0] && x < mx_) { // X if (y >= OXYZ_[1] && y < my_) { // Y From 02f7e8052b9ee24b9f76454364d00b3c125133e6 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 24 Jun 2021 10:24:14 -0400 Subject: [PATCH 11/79] Remove cast to GridBin --- src/Action_Volmap.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Action_Volmap.cpp b/src/Action_Volmap.cpp index 52f1e567c2..24ad456960 100644 --- a/src/Action_Volmap.cpp +++ b/src/Action_Volmap.cpp @@ -214,11 +214,10 @@ Action::RetType Action_Volmap::Init(ArgList& actionArgs, ActionInit& init, int d mprinterr("Error: Currently only works with orthogonal grids.\n"); return Action::ERR; } - GridBin const& gbo = static_cast( grid_->Bin() ); - dx_ = gbo.DX(); - dy_ = gbo.DY(); - dz_ = gbo.DZ(); - Vec3 const& oxyz = gbo.GridOrigin(); + dx_ = grid_->Bin().DX(); + dy_ = grid_->Bin().DY(); + dz_ = grid_->Bin().DZ(); + Vec3 const& oxyz = grid_->Bin().GridOrigin(); xmin_ = oxyz[0]; ymin_ = oxyz[1]; zmin_ = oxyz[2]; From 0ad220a6d6053b99ad3c3ad3735bf2025a780e26 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 24 Jun 2021 11:02:51 -0400 Subject: [PATCH 12/79] Use class function pointers in GridBin to avoid 'if' branching, restores performance for orthogonal grids. --- src/GridBin.h | 62 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/src/GridBin.h b/src/GridBin.h index cef7e0a184..8452f330c9 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -42,20 +42,40 @@ class GridBin { inline void Setup_O_D(size_t, size_t, size_t, Vec3 const&, Vec3 const&); /// Set up for grid with given bins, origin, and box. inline void Setup_O_Box(size_t, size_t, size_t, Vec3 const&, Box const&); - protected: + private: + inline bool Calc_ortho(double, double, double, size_t&, size_t&, size_t&) const; + inline bool Calc_nonortho(double, double, double, size_t&, size_t&, size_t&) const; + inline void Indices_ortho(double, double, double, long int&, long int&, long int&) const; + inline void Indices_nonortho(double, double, double, long int&, long int&, long int&) const; + inline void SetupInternalPointers(); + Vec3 OXYZ_; ///< Grid origin. double dx_, dy_, dz_; ///< Grid spacing (Ang., Cartesian, orthogonal). double mx_, my_, mz_; ///< Grid max (Ang., Cartesian, orthogonal). double nx_, ny_, nz_; ///< Number of bins in double precision (nonortho). double voxelvolume_; ///< Volume of a single voxel (Ang^3). Box box_; ///< Contain grid unit cell vectors, frac. vectors, volume. + + bool (GridBin::*CalcPtr_)(double, double, double, size_t&, size_t&, size_t&) const; + void (GridBin::*IndicesPtr_)(double, double, double, long int&, long int&, long int&) const; }; // ----------------------------------------------------------------------------- +/** Interface to the Calc routine appropriate for the grid type. */ +bool GridBin::Calc(double x, double y, double z, size_t& i, size_t& j, size_t& k) const { + return ((*this).*(CalcPtr_))(x, y, z, i, j, k); +} + +/** Interface to the Indices routine appropriate for the grid type. */ +void GridBin::Indices(double x, double y, double z, long int& i, long int& j, long int& k) const +{ + ((*this).*(IndicesPtr_))(x, y, z, i, j, k); +} + /** \return true if given coordinates are on grid; set corresponding bin indices. */ -bool GridBin::Calc(double x, double y, double z, size_t& i, size_t& j, size_t& k) const +bool GridBin::Calc_ortho(double x, double y, double z, size_t& i, size_t& j, size_t& k) const { - if (box_.Is_X_Aligned_Ortho()) { + //if (box_.Is_X_Aligned_Ortho()) { //mprintf("DEBUG: X-aligned Calc\n"); // X-aligned and orthogonal if (x >= OXYZ_[0] && x < mx_) { // X @@ -68,7 +88,13 @@ bool GridBin::Calc(double x, double y, double z, size_t& i, size_t& j, size_t& k } } } - } else { + //} else { + return false; +} + +/** \return true if given coordinates are on grid; set corresponding bin indices. */ +bool GridBin::Calc_nonortho(double x, double y, double z, size_t& i, size_t& j, size_t& k) const +{ // Not X-aligned or non-orthogonal Vec3 frac = box_.FracCell() * Vec3(x - OXYZ_[0], y - OXYZ_[1], z - OXYZ_[2]); if (frac[0] >= 0.0 && frac[0] < 1.0) { @@ -81,25 +107,30 @@ bool GridBin::Calc(double x, double y, double z, size_t& i, size_t& j, size_t& k } } } - } + //} return false; } /** Given coordinates, set corresponding bin indices; no bounds check. */ -void GridBin::Indices(double x, double y, double z, long int& i, long int& j, long int& k) const +void GridBin::Indices_ortho(double x, double y, double z, long int& i, long int& j, long int& k) const { - if (box_.Is_X_Aligned_Ortho()) { + //if (box_.Is_X_Aligned_Ortho()) { // X-aligned and orthogonal i = (long int)((x-OXYZ_[0]) / dx_); j = (long int)((y-OXYZ_[1]) / dy_); k = (long int)((z-OXYZ_[2]) / dz_); - } else { + //} else { +} + +/** Given coordinates, set corresponding bin indices; no bounds check. */ +void GridBin::Indices_nonortho(double x, double y, double z, long int& i, long int& j, long int& k) const +{ // Not X-aligned or non-orthogonal Vec3 frac = box_.FracCell() * Vec3(x - OXYZ_[0], y - OXYZ_[1], z - OXYZ_[2]); i = (long int)(frac[0] * nx_); j = (long int)(frac[1] * ny_); k = (long int)(frac[2] * nz_); - } + //} } @@ -135,6 +166,17 @@ Vec3 GridBin::Center(long int i, long int j, long int k) const } } +/** Set up function internal pointers. */ +void GridBin::SetupInternalPointers() { + if (box_.Is_X_Aligned_Ortho()) { + CalcPtr_ = &GridBin::Calc_ortho; + IndicesPtr_ = &GridBin::Indices_ortho; + } else { + CalcPtr_ = &GridBin::Calc_nonortho; + IndicesPtr_ = &GridBin::Indices_nonortho; + } +} + /** Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. */ void GridBin::Setup_O_D(size_t nx, size_t ny, size_t nz, Vec3 const& oxyzIn, Vec3 const& dxyz) @@ -166,6 +208,7 @@ void GridBin::Setup_O_D(size_t nx, size_t ny, size_t nz, box_.SetupFromUcell(ucell); box_.PrintDebug("GridBin::Setup_O_D"); + SetupInternalPointers(); } @@ -193,6 +236,7 @@ void GridBin::Setup_O_Box(size_t nxIn, size_t nyIn, size_t nzIn, mz_ = OXYZ_[2] + l_Cvec; // Get voxel volume from total grid volume over number of bins. voxelvolume_ = boxIn.CellVolume() / (nx_ * ny_ * nz_); + SetupInternalPointers(); } #endif From 42f329133e2d8516d49983cd8b61de2f56694f5e Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 24 Jun 2021 11:12:48 -0400 Subject: [PATCH 13/79] Add function pointers for corner and center --- src/GridBin.h | 53 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/src/GridBin.h b/src/GridBin.h index 8452f330c9..60fc17dcef 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -47,6 +47,10 @@ class GridBin { inline bool Calc_nonortho(double, double, double, size_t&, size_t&, size_t&) const; inline void Indices_ortho(double, double, double, long int&, long int&, long int&) const; inline void Indices_nonortho(double, double, double, long int&, long int&, long int&) const; + inline Vec3 Corner_ortho(long int, long int, long int) const; + inline Vec3 Corner_nonortho(long int, long int, long int) const; + inline Vec3 Center_ortho(long int, long int, long int) const; + inline Vec3 Center_nonortho(long int, long int, long int) const; inline void SetupInternalPointers(); Vec3 OXYZ_; ///< Grid origin. @@ -55,9 +59,14 @@ class GridBin { double nx_, ny_, nz_; ///< Number of bins in double precision (nonortho). double voxelvolume_; ///< Volume of a single voxel (Ang^3). Box box_; ///< Contain grid unit cell vectors, frac. vectors, volume. - + /// Internal pointer to the correct Calc routine bool (GridBin::*CalcPtr_)(double, double, double, size_t&, size_t&, size_t&) const; + /// Internal pointer to the correct Indices routine void (GridBin::*IndicesPtr_)(double, double, double, long int&, long int&, long int&) const; + /// Internal pointer to the correct Corner routine + Vec3 (GridBin::*CornerPtr_)(long int, long int, long int) const; + /// Internal pointer to the correct Center routine + Vec3 (GridBin::*CenterPtr_)(long int, long int, long int) const; }; // ----------------------------------------------------------------------------- @@ -72,6 +81,18 @@ void GridBin::Indices(double x, double y, double z, long int& i, long int& j, lo ((*this).*(IndicesPtr_))(x, y, z, i, j, k); } +/** Interface to the Corner routine appropriate for the grid type. */ +Vec3 GridBin::Corner(long int i, long int j, long int k) const +{ + return ((*this).*(CornerPtr_))(i, j, k); +} + +/** Interface to the Center routine appropriate for the grid type. */ +Vec3 GridBin::Center(long int i, long int j, long int k) const +{ + return ((*this).*(CenterPtr_))(i, j, k); +} + /** \return true if given coordinates are on grid; set corresponding bin indices. */ bool GridBin::Calc_ortho(double x, double y, double z, size_t& i, size_t& j, size_t& k) const { @@ -135,35 +156,45 @@ void GridBin::Indices_nonortho(double x, double y, double z, long int& i, long i /** \return coordinates of bin for given indices; no bound check. */ -Vec3 GridBin::Corner(long int i, long int j, long int k) const +Vec3 GridBin::Corner_ortho(long int i, long int j, long int k) const { - if (box_.Is_X_Aligned_Ortho()) { + //if (box_.Is_X_Aligned_Ortho()) { // X-aligned and orthogonal return Vec3((double)i*dx_+OXYZ_[0], (double)j*dy_+OXYZ_[1], (double)k*dz_+OXYZ_[2]); - } else { + //} else { +} + +/** \return coordinates of bin for given indices; no bound check. */ +Vec3 GridBin::Corner_nonortho(long int i, long int j, long int k) const +{ // Not X-aligned or non-orthogonal Vec3 frac( (double)i / nx_, (double)j / ny_, (double)k / nz_ ); return box_.UnitCell().TransposeMult( frac ) + OXYZ_; - } + //} } /** \return coordinates of bin center for given indices; no bounds check. */ -Vec3 GridBin::Center(long int i, long int j, long int k) const +Vec3 GridBin::Center_ortho(long int i, long int j, long int k) const { - if (box_.Is_X_Aligned_Ortho()) { + //if (box_.Is_X_Aligned_Ortho()) { // X-aligned and orthogonal return Vec3((double)i*dx_+OXYZ_[0]+0.5*dx_, (double)j*dy_+OXYZ_[1]+0.5*dy_, (double)k*dz_+OXYZ_[2]+0.5*dz_); - } else { + //} else { +} + +/** \return coordinates of bin center for given indices; no bounds check. */ +Vec3 GridBin::Center_nonortho(long int i, long int j, long int k) const +{ // Not X-aligned or non-orthogonal Vec3 frac_half((1.0 + 2.0 * (double)i) / (2.0 * nx_), //(0.5 * (1.0 / nx_)) + ((double)i / nx_), (1.0 + 2.0 * (double)j) / (2.0 * ny_), (1.0 + 2.0 * (double)k) / (2.0 * nz_)); return box_.UnitCell().TransposeMult( frac_half ) + OXYZ_; - } + //} } /** Set up function internal pointers. */ @@ -171,9 +202,13 @@ void GridBin::SetupInternalPointers() { if (box_.Is_X_Aligned_Ortho()) { CalcPtr_ = &GridBin::Calc_ortho; IndicesPtr_ = &GridBin::Indices_ortho; + CornerPtr_ = &GridBin::Corner_ortho; + CenterPtr_ = &GridBin::Center_ortho; } else { CalcPtr_ = &GridBin::Calc_nonortho; IndicesPtr_ = &GridBin::Indices_nonortho; + CornerPtr_ = &GridBin::Corner_nonortho; + CenterPtr_ = &GridBin::Center_nonortho; } } From 5cd4ab6f3358946a673092efa25b3ac5a7d938b1 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 25 Jun 2021 09:29:38 -0400 Subject: [PATCH 14/79] Start adding ability to extract box params from grid instead of frame --- src/Action_Vector.cpp | 19 +++++++++++++++++++ src/Action_Vector.h | 2 ++ src/cpptrajdepend | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Action_Vector.cpp b/src/Action_Vector.cpp index 3bb73512c2..e67c27f8ac 100644 --- a/src/Action_Vector.cpp +++ b/src/Action_Vector.cpp @@ -5,11 +5,13 @@ #include "CpptrajStdio.h" #include "DistRoutines.h" // MinImagedVec, includes Matrix_3x3 for principal #include "DataSet_Vector.h" +#include "DataSet_3D.h" // CONSTRUCTOR Action_Vector::Action_Vector() : Vec_(0), Magnitude_(0), + gridSet_(0), vcorr_(0), ptrajoutput_(false), needBoxInfo_(false), @@ -137,6 +139,21 @@ Action::RetType Action_Vector::Init(ArgList& actionArgs, ActionInit& init, int d if (mode_ == BOX || mode_ == BOX_X || mode_ == BOX_Y || mode_ == BOX_Z || mode_ == BOX_CTR || mode_ == MINIMAGE) needBoxInfo_ = true; + gridSet_ = 0; + if (needBoxInfo_) { + std::string gridSetArg = actionArgs.GetStringKey("gridset"); + if (!gridSetArg.empty()) { + DataSetList gridSetList = init.DSL().SelectGroupSets( gridSetArg, DataSet::GRID_3D ); + if (gridSetList.empty()) { + mprinterr("Error: %s does not select any grid data set.\n", gridSetArg.c_str()); + return Action::ERR; + } + if (gridSetList.size() > 1) { + mprintf("Warning: %s selects more than 1 grid data set. Only using the first set.\n", gridSetArg.c_str()); + } + gridSet_ = (DataSet_3D*)gridSetList[0]; + } + } // Check if IRED vector bool isIred = actionArgs.hasKey("ired"); // Vector Mask @@ -190,6 +207,8 @@ Action::RetType Action_Vector::Init(ArgList& actionArgs, ActionInit& init, int d mprintf(" %s", filename.c_str()); } mprintf("\n"); + if (gridSet_ != 0) + mprintf("\tExtracting box vectors from grid set '%s'\n", gridSet_->legend()); return Action::OK; } diff --git a/src/Action_Vector.h b/src/Action_Vector.h index efbf91d1e3..23cdbc7161 100644 --- a/src/Action_Vector.h +++ b/src/Action_Vector.h @@ -2,6 +2,7 @@ #define INC_ACTION_VECTOR_H #include "Action.h" class DataSet_Vector; +class DataSet_3D; class Action_Vector : public Action { public: Action_Vector(); @@ -34,6 +35,7 @@ class Action_Vector : public Action { DataSet_Vector* Vec_; ///< Hold vector values DataSet* Magnitude_; ///< Hold vector magnitudes if requested + DataSet_3D* gridSet_; ///< Hold grid set for getting box vectors from grid. double* vcorr_; ///< Temp. space for calculating CorrPlane vectorMode mode_; ///< Vector calculation mode bool ptrajoutput_; ///< If true output in ptraj format diff --git a/src/cpptrajdepend b/src/cpptrajdepend index 421b1bd6a6..f2570a48b4 100644 --- a/src/cpptrajdepend +++ b/src/cpptrajdepend @@ -82,7 +82,7 @@ Action_Time.o : Action_Time.cpp Action.h ActionState.h Action_Time.h ArgList.h A Action_Translate.o : Action_Translate.cpp Action.h ActionState.h Action_Translate.h ArgList.h AssociatedData.h Atom.h AtomMask.h AtomType.h BaseIOtype.h Box.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataFile.h DataFileList.h DataSet.h DataSetList.h DataSet_Coords.h DataSet_Coords_REF.h Dimension.h DispatchObject.h FileIO.h FileName.h FileTypes.h Frame.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h TextFormat.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h Action_Unstrip.o : Action_Unstrip.cpp Action.h ActionState.h Action_Unstrip.h ArgList.h AssociatedData.h Atom.h AtomMask.h AtomType.h BaseIOtype.h Box.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataFile.h DataFileList.h DataSet.h DataSetList.h DataSet_Coords.h DataSet_Coords_REF.h Dimension.h DispatchObject.h FileIO.h FileName.h FileTypes.h Frame.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h TextFormat.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h Action_Unwrap.o : Action_Unwrap.cpp Action.h ActionState.h Action_Unwrap.h ArgList.h AssociatedData.h Atom.h AtomMask.h AtomType.h BaseIOtype.h Box.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataFile.h DataFileList.h DataSet.h DataSetList.h DataSet_Coords.h DataSet_Coords_REF.h Dimension.h DispatchObject.h FileIO.h FileName.h FileTypes.h Frame.h ImageRoutines.h ImageTypes.h Image_List.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h TextFormat.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h -Action_Vector.o : Action_Vector.cpp Action.h ActionState.h Action_Vector.h ArgList.h ArrayIterator.h AssociatedData.h Atom.h AtomMask.h AtomType.h BaseIOtype.h Box.h ComplexArray.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataFile.h DataFileList.h DataSet.h DataSetList.h DataSet_Coords.h DataSet_Coords_REF.h DataSet_Vector.h Dimension.h DispatchObject.h DistRoutines.h FileIO.h FileName.h FileTypes.h Frame.h ImageOption.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h TextFormat.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h +Action_Vector.o : Action_Vector.cpp Action.h ActionState.h Action_Vector.h ArgList.h ArrayIterator.h AssociatedData.h Atom.h AtomMask.h AtomType.h BaseIOtype.h Box.h ComplexArray.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataFile.h DataFileList.h DataSet.h DataSetList.h DataSet_3D.h DataSet_Coords.h DataSet_Coords_REF.h DataSet_Vector.h Dimension.h DispatchObject.h DistRoutines.h FileIO.h FileName.h FileTypes.h Frame.h GridBin.h ImageOption.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h TextFormat.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h Action_VelocityAutoCorr.o : Action_VelocityAutoCorr.cpp Action.h ActionState.h Action_VelocityAutoCorr.h ArgList.h ArrayIterator.h AssociatedData.h Atom.h AtomMask.h AtomType.h BaseIOtype.h Box.h ComplexArray.h Constants.h CoordinateInfo.h Corr.h CpptrajFile.h CpptrajStdio.h DataFile.h DataFileList.h DataSet.h DataSetList.h DataSet_1D.h DataSet_Coords.h DataSet_Coords_REF.h DataSet_Vector.h DataSet_double.h Dimension.h DispatchObject.h FileIO.h FileName.h FileTypes.h Frame.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h ProgressBar.h PubFFT.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h TextFormat.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h Action_Volmap.o : Action_Volmap.cpp Action.h ActionState.h Action_Volmap.h ArgList.h ArrayIterator.h AssociatedData.h Atom.h AtomMask.h AtomType.h BaseIOtype.h Box.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataFile.h DataFileList.h DataSet.h DataSetList.h DataSet_3D.h DataSet_Coords.h DataSet_Coords_REF.h DataSet_GridDbl.h DataSet_GridFlt.h Dimension.h DispatchObject.h FileIO.h FileName.h FileTypes.h Frame.h Grid.h GridBin.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h Segment.h SplineFxnTable.h SymbolExporting.h TextFormat.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h Action_Volume.o : Action_Volume.cpp Action.h ActionState.h Action_Volume.h ArgList.h AssociatedData.h Atom.h AtomMask.h AtomType.h BaseIOtype.h Box.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataFile.h DataFileList.h DataSet.h DataSetList.h DataSet_1D.h DataSet_Coords.h DataSet_Coords_REF.h Dimension.h DispatchObject.h FileIO.h FileName.h FileTypes.h Frame.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h TextFormat.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h From d6074b9bc8ab9e0a1c31f2d08b060c3428f118b7 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 25 Jun 2021 09:34:36 -0400 Subject: [PATCH 15/79] Add BoxLengths function --- src/Action_Vector.cpp | 11 ++++++++--- src/Action_Vector.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Action_Vector.cpp b/src/Action_Vector.cpp index e67c27f8ac..43b9efc918 100644 --- a/src/Action_Vector.cpp +++ b/src/Action_Vector.cpp @@ -22,12 +22,12 @@ Action_Vector::Action_Vector() : // Action_Vector::Help() void Action_Vector::Help() const { mprintf("\t[] [out [ptrajoutput]] [] []\n" - "\t[magnitude] [ired]\n" + "\t[magnitude] [ired] [gridset ]\n" "\t = { mask | minimage | dipole | center | corrplane | \n" "\t box | boxcenter | ucellx | ucelly | ucellz | \n" "\t momentum | principal [x|y|z] | velocity | force }\n" - " Calculate the specified coordinate vector.\n" - " mask: (Default) Vector from to .\n" + " Calculate the vector of specified :\n" + " mask : (Default) Vector from to .\n" " minimage : Store the minimum image vector between atoms in and .\n" " dipole : Dipole and center of mass of the atoms specified in \n" " center : Store the center of mass of atoms in .\n" @@ -447,6 +447,11 @@ void Action_Vector::UnitCell(Box const& box) { } } +/** Store box vector (A, B, C) lengths as a single vector (|A|, |B|, |C|). */ +void Action_Vector::BoxLengths(Box const& box) { + Vec_->AddVxyz( box.Lengths() ); +} + // Action_Vector::MinImage() void Action_Vector::MinImage(Frame const& frm) { Vec3 com1 = frm.VCenterOfMass(mask_); diff --git a/src/Action_Vector.h b/src/Action_Vector.h index 23cdbc7161..93de031609 100644 --- a/src/Action_Vector.h +++ b/src/Action_Vector.h @@ -31,6 +31,7 @@ class Action_Vector : public Action { void Principal(Frame const&); void CorrPlane(Frame const&); void UnitCell(Box const&); + void BoxLengths(Box const&); void MinImage(Frame const&); DataSet_Vector* Vec_; ///< Hold vector values From 5369c05584af0f2737e4a5dd0dfd6bb622b6b472 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 25 Jun 2021 09:35:44 -0400 Subject: [PATCH 16/79] Use BoxLengths function --- src/Action_Vector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Action_Vector.cpp b/src/Action_Vector.cpp index 43b9efc918..b71d6e22b5 100644 --- a/src/Action_Vector.cpp +++ b/src/Action_Vector.cpp @@ -485,7 +485,7 @@ Action::RetType Action_Vector::DoAction(int frameNum, ActionFrame& frm) { case PRINCIPAL_Y : case PRINCIPAL_Z : Principal(frm.Frm()); break; case CORRPLANE : CorrPlane(frm.Frm()); break; - case BOX : Vec_->AddVxyz( frm.Frm().BoxCrd().Lengths() ); break; + case BOX : BoxLengths( frm.Frm().BoxCrd() ); break; case BOX_X : case BOX_Y : case BOX_Z : From acf34ad223fd3d7cd6885b63b6a8f3182d0e3595 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 25 Jun 2021 09:39:29 -0400 Subject: [PATCH 17/79] Use gridSet where appropriate --- src/Action_Vector.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Action_Vector.cpp b/src/Action_Vector.cpp index b71d6e22b5..244af0a958 100644 --- a/src/Action_Vector.cpp +++ b/src/Action_Vector.cpp @@ -485,11 +485,21 @@ Action::RetType Action_Vector::DoAction(int frameNum, ActionFrame& frm) { case PRINCIPAL_Y : case PRINCIPAL_Z : Principal(frm.Frm()); break; case CORRPLANE : CorrPlane(frm.Frm()); break; - case BOX : BoxLengths( frm.Frm().BoxCrd() ); break; + case BOX : + if (gridSet_ != 0) + BoxLengths( gridSet_->Bin().GridBox() ); + else + BoxLengths( frm.Frm().BoxCrd() ); + break; case BOX_X : case BOX_Y : case BOX_Z : - case BOX_CTR : UnitCell( frm.Frm().BoxCrd() ); break; + case BOX_CTR : + if (gridSet_ != 0) + UnitCell( gridSet_->Bin().GridBox() ); + else + UnitCell( frm.Frm().BoxCrd() ); + break; case MINIMAGE : MinImage( frm.Frm() ); break; default : return Action::ERR; // NO_OP } // END switch over vectorMode From bd557af3bb08e77b0e5489a7bad51db9baa000f2 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 25 Jun 2021 10:39:41 -0400 Subject: [PATCH 18/79] Fix origin for ucell vecs from grids --- src/Action_Vector.cpp | 12 ++++++------ src/Action_Vector.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Action_Vector.cpp b/src/Action_Vector.cpp index 244af0a958..def85647e7 100644 --- a/src/Action_Vector.cpp +++ b/src/Action_Vector.cpp @@ -437,11 +437,11 @@ void Action_Vector::CorrPlane(Frame const& currentFrame) { } // Action_Vector::UnitCell() -void Action_Vector::UnitCell(Box const& box) { +void Action_Vector::UnitCell(Box const& box, Vec3 const& oxyz) { switch ( mode_ ) { - case BOX_X : Vec_->AddVxyzo( box.UnitCell().Row1(), Vec3(0.0) ); break; - case BOX_Y : Vec_->AddVxyzo( box.UnitCell().Row2(), Vec3(0.0) ); break; - case BOX_Z : Vec_->AddVxyzo( box.UnitCell().Row3(), Vec3(0.0) ); break; + case BOX_X : Vec_->AddVxyzo( box.UnitCell().Row1(), oxyz ); break; + case BOX_Y : Vec_->AddVxyzo( box.UnitCell().Row2(), oxyz ); break; + case BOX_Z : Vec_->AddVxyzo( box.UnitCell().Row3(), oxyz ); break; case BOX_CTR : Vec_->AddVxyz( box.UnitCell().TransposeMult(Vec3(0.5)) ); break; default: return; } @@ -496,9 +496,9 @@ Action::RetType Action_Vector::DoAction(int frameNum, ActionFrame& frm) { case BOX_Z : case BOX_CTR : if (gridSet_ != 0) - UnitCell( gridSet_->Bin().GridBox() ); + UnitCell( gridSet_->Bin().GridBox(), gridSet_->Bin().GridOrigin() ); else - UnitCell( frm.Frm().BoxCrd() ); + UnitCell( frm.Frm().BoxCrd(), Vec3(0.0) ); break; case MINIMAGE : MinImage( frm.Frm() ); break; default : return Action::ERR; // NO_OP diff --git a/src/Action_Vector.h b/src/Action_Vector.h index 93de031609..471bc79e72 100644 --- a/src/Action_Vector.h +++ b/src/Action_Vector.h @@ -30,7 +30,7 @@ class Action_Vector : public Action { void Dipole(Frame const&); void Principal(Frame const&); void CorrPlane(Frame const&); - void UnitCell(Box const&); + void UnitCell(Box const&, Vec3 const&); void BoxLengths(Box const&); void MinImage(Frame const&); From dedd42293b5470318933c554d84f7a8ac1e9ec78 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 25 Jun 2021 10:41:40 -0400 Subject: [PATCH 19/79] Add gridset keyword to vector documentation --- doc/cpptraj.lyx | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/doc/cpptraj.lyx b/doc/cpptraj.lyx index 14307c0bf8..eb0ed4cc3d 100644 --- a/doc/cpptraj.lyx +++ b/doc/cpptraj.lyx @@ -36386,7 +36386,7 @@ vector [] [out [ptrajoutput]] [] [] \end_layout \begin_layout LyX-Code - [magnitude] [ired] + [magnitude] [ired] [gridset ] \end_layout \begin_layout LyX-Code @@ -36469,6 +36469,27 @@ ptraj ired' and 'ired'. \end_layout +\begin_layout Description +[gridset +\begin_inset space ~ +\end_inset + +] Name of grid data set to get box info from instead of frame for + +\series bold +box +\series default +, +\series bold +boxcenter +\series default +, and +\series bold +ucell[x|y|z] +\series default +. +\end_layout + \begin_layout Standard Data Sets Created: \end_layout From 0a71203637d8803e922d2d3e1a60534d3fde722d Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 25 Jun 2021 11:38:53 -0400 Subject: [PATCH 20/79] Change GridMode to OffsetType, better describes what it is actually used for. Add more code documentation --- src/Action_Dipole.cpp | 6 +++--- src/Action_Grid.cpp | 4 ++-- src/DataSet_3D.cpp | 2 +- src/GridAction.cpp | 24 ++++++++++++------------ src/GridAction.h | 24 +++++++++++++++++------- 5 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/Action_Dipole.cpp b/src/Action_Dipole.cpp index 83e43965fd..4fdf5f05e8 100644 --- a/src/Action_Dipole.cpp +++ b/src/Action_Dipole.cpp @@ -105,11 +105,11 @@ Action::RetType Action_Dipole::DoAction(int frameNum, ActionFrame& frm) { Vec3 cXYZ, dipolar_vector, COM; // Set up center to origin or box center - if (GridMode() == GridAction::BOX) + if (GridOffsetType() == GridAction::BOX_CENTER) cXYZ = frm.Frm().BoxCrd().Center(); - else if (GridMode() == GridAction::MASKCENTER) + else if (GridOffsetType() == GridAction::MASK_CENTER) cXYZ = frm.Frm().VGeometricCenter( CenterMask() ); - else // GridAction::ORIGIN/SPECIFIEDCENTER + else // GridAction::NO_OFFSET cXYZ.Zero(); // Traverse over solvent molecules. diff --git a/src/Action_Grid.cpp b/src/Action_Grid.cpp index 2b3381d91e..b11ace4a5b 100644 --- a/src/Action_Grid.cpp +++ b/src/Action_Grid.cpp @@ -130,9 +130,9 @@ Action::RetType Action_Grid::Setup(ActionSetup& setup) { Action::RetType Action_Grid::DoAction(int frameNum, ActionFrame& frm) { if (useMaskArray_) { Vec3 offset(0.0); - if (GridMode() == BOX) + if (GridOffsetType() == BOX_CENTER) offset = frm.Frm().BoxCrd().Center(); - else if (GridMode() == MASKCENTER) + else if (GridOffsetType() == MASK_CENTER) offset = frm.Frm().VGeometricCenter( CenterMask() ); for (Cpptraj::MaskArray::const_iterator mask = mArray_.begin(); mask != mArray_.end(); ++mask) diff --git a/src/DataSet_3D.cpp b/src/DataSet_3D.cpp index 1f791bec55..0d04a1985b 100644 --- a/src/DataSet_3D.cpp +++ b/src/DataSet_3D.cpp @@ -95,7 +95,7 @@ void DataSet_3D::GridInfo() const { oxyz[0] + (NX()/2)*gridBin_.DX(), oxyz[1] + (NY()/2)*gridBin_.DY(), oxyz[2] + (NZ()/2)*gridBin_.DZ()); - //mprintf("\tGrid max : %8.3f %8.3f %8.3f\n", grid.MX(), grid.MY(), grid.MZ()); + //mprintf("\tGrid max : %8.3f %8.3f %8.3f\n", gridBin_.MX(), gridBin_.MY(), gridBin_.MZ()); //} else { Box const& box = gridBin_.GridBox(); mprintf("\t\tBox: %s ABC={%g %g %g} abg={%g %g %g}\n", box.CellShapeName(), diff --git a/src/GridAction.cpp b/src/GridAction.cpp index 9b90847204..48464d8861 100644 --- a/src/GridAction.cpp +++ b/src/GridAction.cpp @@ -89,11 +89,11 @@ DataSet_GridFlt* GridAction::GridInit(const char* callingRoutine, ArgList& argIn if (Grid->Allocate_N_C_D(nx, ny, nz, gridctr, Vec3(dx,dy,dz))) return 0; } // Determine offset, Box/origin/center - mode_ = ORIGIN; + gridOffsetType_ = NO_OFFSET; if (argIn.hasKey("box")) - mode_ = BOX; + gridOffsetType_ = BOX_CENTER; else if (argIn.hasKey("origin")) - mode_ = ORIGIN; + gridOffsetType_ = NO_OFFSET; else if (argIn.Contains("center")) { std::string maskexpr = argIn.GetStringKey("center"); if (maskexpr.empty()) { @@ -101,14 +101,14 @@ DataSet_GridFlt* GridAction::GridInit(const char* callingRoutine, ArgList& argIn return 0; } if (centerMask_.SetMaskString( maskexpr )) return 0; - mode_ = MASKCENTER; + gridOffsetType_ = MASK_CENTER; } if (specifiedCenter) { // If center was specified, do not allow an offset - if (mode_ != ORIGIN) + if (gridOffsetType_ != NO_OFFSET) mprintf("Warning: Grid offset args (box/center) not allowed with 'gridcenter'.\n" "Warning: No offset will be used.\n"); - mode_ = SPECIFIEDCENTER; + gridOffsetType_ = NO_OFFSET; } // Negative if (argIn.hasKey("negative")) @@ -132,9 +132,9 @@ int GridAction::ParallelGridInit(Parallel::Comm const& commIn, DataSet_GridFlt* // GridAction::GridInfo() void GridAction::GridInfo(DataSet_GridFlt const& grid) { - if (mode_ == BOX) + if (gridOffsetType_ == BOX_CENTER) mprintf("\tOffset for points is box center.\n"); - else if (mode_ == MASKCENTER) + else if (gridOffsetType_ == MASK_CENTER) mprintf("\tOffset for points is center of atoms in mask [%s]\n", centerMask_.MaskString()); if (increment_ > 0) @@ -147,14 +147,14 @@ void GridAction::GridInfo(DataSet_GridFlt const& grid) { // GridAction::GridSetup() int GridAction::GridSetup(Topology const& currentParm, CoordinateInfo const& cInfo) { // Check box - if (mode_ == BOX) { + if (gridOffsetType_ == BOX_CENTER) { if (!cInfo.TrajBox().Is_X_Aligned_Ortho()) { mprintf("Warning: Code to shift to the box center is not yet\n"); mprintf("Warning: implemented for non-orthorhombic unit cells.\n"); - mprintf("Warning: Shifting to the origin instead.\n"); - mode_ = ORIGIN; + mprintf("Warning: No offset will be used.\n"); + gridOffsetType_ = NO_OFFSET; // TODO Error? } - } else if (mode_ == MASKCENTER) { + } else if (gridOffsetType_ == MASK_CENTER) { if ( currentParm.SetupIntegerMask( centerMask_ ) ) return 1; centerMask_.MaskInfo(); if ( centerMask_.None() ) { diff --git a/src/GridAction.h b/src/GridAction.h index a57930a77e..7ed0a88356 100644 --- a/src/GridAction.h +++ b/src/GridAction.h @@ -11,22 +11,32 @@ class CoordinateInfo; /// Class for setting up a grid within an action. class GridAction { public: - /// Indicate which kind of gridding to perform - enum GridModeType { ORIGIN = 0, BOX, MASKCENTER, SPECIFIEDCENTER }; + /// Indicate whether to apply an offset to coords before gridding. + enum OffsetType { NO_OFFSET = 0, BOX_CENTER, MASK_CENTER }; + /// CONSTRUCTOR GridAction() : increment_(1.0) {} + /// \return List of keywords recognized by GridInit. static const char* HelpText; + /// \return Set-up grid (added to given DataSetList) after processing keywords. DataSet_GridFlt* GridInit(const char*, ArgList&, DataSetList&); # ifdef MPI + /// Perform any parallel initialization int ParallelGridInit(Parallel::Comm const&, DataSet_GridFlt*); # endif + /// Print information on given grid to STDOUT void GridInfo(DataSet_GridFlt const&); + /// Perform any setup necessary for given Topology/CoordinateInfo int GridSetup(Topology const&, CoordinateInfo const&); + /// Place atoms selected by given mask in given Frame on the given grid. inline void GridFrame(Frame const&, AtomMask const&, DataSet_GridFlt&); - GridModeType GridMode() const { return mode_; } + /// \return Type of offset to apply to coords before gridding. + OffsetType GridOffsetType() const { return gridOffsetType_; } + /// \return Mask to use for centering grid AtomMask const& CenterMask() const { return centerMask_; } + /// \return Amount voxels should be incremented by float Increment() const { return increment_; } private: - GridModeType mode_; + OffsetType gridOffsetType_; AtomMask centerMask_; float increment_; ///< Set to -1 if negative, 1 if not. }; @@ -34,15 +44,15 @@ class GridAction { void GridAction::GridFrame(Frame const& currentFrame, AtomMask const& mask, DataSet_GridFlt& grid) { - if (mode_==BOX) { + if (gridOffsetType_ == BOX_CENTER) { Vec3 offset = currentFrame.BoxCrd().Center(); for (AtomMask::const_iterator atom = mask.begin(); atom != mask.end(); ++atom) grid.Increment( Vec3(currentFrame.XYZ(*atom)) - offset, increment_ ); - } else if (mode_==MASKCENTER) { + } else if (gridOffsetType_ == MASK_CENTER) { Vec3 offset = currentFrame.VGeometricCenter( centerMask_ ); for (AtomMask::const_iterator atom = mask.begin(); atom != mask.end(); ++atom) grid.Increment( Vec3(currentFrame.XYZ(*atom)) - offset, increment_ ); - } else {// mode_==ORIGIN/SPECIFIEDCENTER, no offset + } else {// mode_==NO_OFFSET for (AtomMask::const_iterator atom = mask.begin(); atom != mask.end(); ++atom) grid.Increment( currentFrame.XYZ(*atom), increment_ ); } From 672f0ab35124906e35292246673190743ccdb8cd Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 25 Jun 2021 11:48:38 -0400 Subject: [PATCH 21/79] Create calcOriginFromCenter function, add missing include cstddef --- src/DataSet_3D.cpp | 15 ++++++++++++++- src/DataSet_3D.h | 3 +++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/DataSet_3D.cpp b/src/DataSet_3D.cpp index 0d04a1985b..906680a1b3 100644 --- a/src/DataSet_3D.cpp +++ b/src/DataSet_3D.cpp @@ -62,15 +62,28 @@ static double Calc_Origin(int N, double D) { return -((double)half * D); } +/** \return Origin coords calculated from given center coords, spacings, and # of bins. */ +Vec3 DataSet_3D::calcOriginFromCenter(Vec3 const& cxyz, Vec3 const& dxyz, + size_t nx, size_t ny, size_t nz) +{ + return Vec3( cxyz[0] + Calc_Origin(nx, dxyz[0]), + cxyz[1] + Calc_Origin(ny, dxyz[1]), + cxyz[2] + Calc_Origin(nz, dxyz[2]) ); +} + // DataSet_3D::Allocate_N_C_D() int DataSet_3D::Allocate_N_C_D(size_t nx, size_t ny, size_t nz, Vec3 const& cxyz, Vec3 const& dxyz) { // Calculate origin from center coordinates. + return Allocate_N_O_D(nx, ny, nz, + calcOriginFromCenter(cxyz, dxyz, nx, ny, nz), + dxyz); +/* Vec3 oxyz( cxyz[0] + Calc_Origin(nx, dxyz[0]), cxyz[1] + Calc_Origin(ny, dxyz[1]), cxyz[2] + Calc_Origin(nz, dxyz[2]) ); - return Allocate_N_O_D(nx,ny,nz,oxyz,dxyz); + return Allocate_N_O_D(nx,ny,nz,oxyz,dxyz);*/ } // DataSet_3D::Allocate_X_C_D() diff --git a/src/DataSet_3D.h b/src/DataSet_3D.h index 15b5647457..3a68f71bc5 100644 --- a/src/DataSet_3D.h +++ b/src/DataSet_3D.h @@ -1,5 +1,6 @@ #ifndef INC_DATASET_3D_H #define INC_DATASET_3D_H +#include // size_t #include "DataSet.h" #include "GridBin.h" class Box; @@ -72,6 +73,8 @@ class DataSet_3D : public DataSet { /// Set up grid for given # x, y, and z points. // TODO: Make public if grids will be used for other than binning. virtual int Allocate3D(size_t, size_t, size_t) = 0; + /// \return Origin coords from center, spacing, and sizes + static Vec3 calcOriginFromCenter(Vec3 const&, Vec3 const&, size_t, size_t, size_t); GridBin gridBin_; ///< Used to calculate bins/coords depending on grid type. }; From fde347cc22ece03b5d861a4cf3d4354219c2851a Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 25 Jun 2021 11:53:19 -0400 Subject: [PATCH 22/79] Add SetOrigin function --- src/GridBin.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/GridBin.h b/src/GridBin.h index 60fc17dcef..6e8163a3fd 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -38,6 +38,7 @@ class GridBin { inline double DZ() const { return dz_; } // Set up routines. + inline void SetOrigin(Vec3 const&); /// Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. inline void Setup_O_D(size_t, size_t, size_t, Vec3 const&, Vec3 const&); /// Set up for grid with given bins, origin, and box. @@ -212,6 +213,24 @@ void GridBin::SetupInternalPointers() { } } +/** Set new origin for grid, update max. */ +void GridBin::SetOrigin(Vec3 const& newOxyz) { + OXYZ_ = newOxyz; + if (box_.Is_X_Aligned_Ortho()) { + mx_ = OXYZ_[0] + (nx_ * dx_); + my_ = OXYZ_[1] + (ny_ * dy_); + mz_ = OXYZ_[2] + (nz_ * dz_); + } else { + double l_Avec = box_.UnitCell().Row1().Length(); + double l_Bvec = box_.UnitCell().Row2().Length(); + double l_Cvec = box_.UnitCell().Row3().Length(); + // Get max from origin plus vector length + mx_ = OXYZ_[0] + l_Avec; + my_ = OXYZ_[1] + l_Bvec; + mz_ = OXYZ_[2] + l_Cvec; + } +} + /** Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. */ void GridBin::Setup_O_D(size_t nx, size_t ny, size_t nz, Vec3 const& oxyzIn, Vec3 const& dxyz) From 3ea2a4c46dde617c9d10981cd05b8485c182002b Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 25 Jun 2021 13:13:12 -0400 Subject: [PATCH 23/79] Start adding code to move the grid --- src/DataSet_3D.cpp | 25 +++++++++++++++++-------- src/DataSet_3D.h | 4 +++- src/GridAction.cpp | 7 +++++++ src/GridAction.h | 14 +++++++++++++- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/DataSet_3D.cpp b/src/DataSet_3D.cpp index 906680a1b3..6cb26b9056 100644 --- a/src/DataSet_3D.cpp +++ b/src/DataSet_3D.cpp @@ -53,9 +53,9 @@ int DataSet_3D::Allocate_N_O_D(size_t nx, size_t ny, size_t nz, /** For even-spaced grids, origin is center - (N/2)*spacing. * For odd-spaced grids, origin is center - ((N-1/2)*spacing)+half_spacing */ -static double Calc_Origin(int N, double D) { - int odd = N % 2; - int half = (N - odd) / 2; +static double Calc_Origin(size_t N, double D) { + size_t odd = N % 2; + size_t half = (N - odd) / 2; if (odd) return -(((double)half * D) + (D * 0.5)); else @@ -63,12 +63,13 @@ static double Calc_Origin(int N, double D) { } /** \return Origin coords calculated from given center coords, spacings, and # of bins. */ -Vec3 DataSet_3D::calcOriginFromCenter(Vec3 const& cxyz, Vec3 const& dxyz, +Vec3 DataSet_3D::calcOriginFromCenter(Vec3 const& cxyz, + double dx, double dy, double dz, size_t nx, size_t ny, size_t nz) { - return Vec3( cxyz[0] + Calc_Origin(nx, dxyz[0]), - cxyz[1] + Calc_Origin(ny, dxyz[1]), - cxyz[2] + Calc_Origin(nz, dxyz[2]) ); + return Vec3( cxyz[0] + Calc_Origin(nx, dx), + cxyz[1] + Calc_Origin(ny, dy), + cxyz[2] + Calc_Origin(nz, dz) ); } // DataSet_3D::Allocate_N_C_D() @@ -77,7 +78,7 @@ int DataSet_3D::Allocate_N_C_D(size_t nx, size_t ny, size_t nz, { // Calculate origin from center coordinates. return Allocate_N_O_D(nx, ny, nz, - calcOriginFromCenter(cxyz, dxyz, nx, ny, nz), + calcOriginFromCenter(cxyz, dxyz[0], dxyz[1], dxyz[2], nx, ny, nz), dxyz); /* Vec3 oxyz( cxyz[0] + Calc_Origin(nx, dxyz[0]), @@ -96,6 +97,14 @@ int DataSet_3D::Allocate_X_C_D(Vec3 const& sizes, Vec3 const& center, Vec3 const return Allocate_N_C_D( nx, ny, nz, center, dxyz ); } +/** Set the center of the grid to given coords via moving the grid origin. */ +void DataSet_3D::SetGridCenter(Vec3 const& cxyz) { + gridBin_.SetOrigin( calcOriginFromCenter(cxyz, + gridBin_.DX(), gridBin_.DY(), gridBin_.DZ(), + NX(), NY(), NZ()) + ); +} + // DataSet_3D::GridInfo() void DataSet_3D::GridInfo() const { Vec3 const& oxyz = gridBin_.GridOrigin(); diff --git a/src/DataSet_3D.h b/src/DataSet_3D.h index 3a68f71bc5..feedd50e92 100644 --- a/src/DataSet_3D.h +++ b/src/DataSet_3D.h @@ -63,6 +63,8 @@ class DataSet_3D : public DataSet { int Allocate_X_C_D(Vec3 const&,Vec3 const&,Vec3 const&); /// Set up grid from dims, origin, and box. int Allocate_N_O_Box(size_t,size_t,size_t, Vec3 const&, Box const&); + /// Move grid center + void SetGridCenter(Vec3 const&); /// Print grid info. void GridInfo() const; // ------------------------------------------- @@ -74,7 +76,7 @@ class DataSet_3D : public DataSet { // TODO: Make public if grids will be used for other than binning. virtual int Allocate3D(size_t, size_t, size_t) = 0; /// \return Origin coords from center, spacing, and sizes - static Vec3 calcOriginFromCenter(Vec3 const&, Vec3 const&, size_t, size_t, size_t); + static Vec3 calcOriginFromCenter(Vec3 const&, double, double, double, size_t, size_t, size_t); GridBin gridBin_; ///< Used to calculate bins/coords depending on grid type. }; diff --git a/src/GridAction.cpp b/src/GridAction.cpp index 48464d8861..ed1dfcdb6c 100644 --- a/src/GridAction.cpp +++ b/src/GridAction.cpp @@ -2,6 +2,13 @@ #include "CpptrajStdio.h" #include "ArgList.h" +/** CONSTRUCTOR */ +GridAction::GridAction() : + gridOffsetType_(NO_OFFSET), + gridMoveType_(NO_OFFSET), + increment_(1.0) +{} + // GridAction::HelpText const char* GridAction::HelpText = "\t{ data | boxref |\n" diff --git a/src/GridAction.h b/src/GridAction.h index 7ed0a88356..eb8ad8d0b3 100644 --- a/src/GridAction.h +++ b/src/GridAction.h @@ -14,7 +14,7 @@ class GridAction { /// Indicate whether to apply an offset to coords before gridding. enum OffsetType { NO_OFFSET = 0, BOX_CENTER, MASK_CENTER }; /// CONSTRUCTOR - GridAction() : increment_(1.0) {} + GridAction(); /// \return List of keywords recognized by GridInit. static const char* HelpText; /// \return Set-up grid (added to given DataSetList) after processing keywords. @@ -29,6 +29,8 @@ class GridAction { int GridSetup(Topology const&, CoordinateInfo const&); /// Place atoms selected by given mask in given Frame on the given grid. inline void GridFrame(Frame const&, AtomMask const&, DataSet_GridFlt&); + /// Move grid if necessary + inline void MoveGrid(Frame const&, DataSet_GridFlt&); /// \return Type of offset to apply to coords before gridding. OffsetType GridOffsetType() const { return gridOffsetType_; } /// \return Mask to use for centering grid @@ -37,6 +39,7 @@ class GridAction { float Increment() const { return increment_; } private: OffsetType gridOffsetType_; + OffsetType gridMoveType_; AtomMask centerMask_; float increment_; ///< Set to -1 if negative, 1 if not. }; @@ -57,4 +60,13 @@ void GridAction::GridFrame(Frame const& currentFrame, AtomMask const& mask, grid.Increment( currentFrame.XYZ(*atom), increment_ ); } } + +/** Move grid if necessary. */ +void GridAction::MoveGrid(Frame const& currentFrame, DataSet_GridFlt& grid) +{ + if (gridMoveType_ == BOX_CENTER) + grid.SetGridCenter( currentFrame.BoxCrd().Center() ); + else if (gridMoveType_ == MASK_CENTER) + grid.SetGridCenter( currentFrame.VGeometricCenter( centerMask_ ) ); +} #endif From e6ae0116cc97a5e1e4dd5e1b2ec8d9539850da4e Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 25 Jun 2021 13:24:10 -0400 Subject: [PATCH 24/79] Add boxcenter and maskcenter keywords --- src/GridAction.cpp | 18 +++++++++++++++++- src/cpptrajdepend | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/GridAction.cpp b/src/GridAction.cpp index ed1dfcdb6c..467cf9e3c3 100644 --- a/src/GridAction.cpp +++ b/src/GridAction.cpp @@ -1,6 +1,7 @@ #include "GridAction.h" #include "CpptrajStdio.h" #include "ArgList.h" +#include "StringRoutines.h" /** CONSTRUCTOR */ GridAction::GridAction() : @@ -12,7 +13,10 @@ GridAction::GridAction() : // GridAction::HelpText const char* GridAction::HelpText = "\t{ data | boxref |\n" - "\t [gridcenter ] }\n" + "\t \n" + "\t [ { gridcenter |\n" + "\t boxcenter |\n" + "\t maskcenter } ]\n" "\t[box|origin|center ] [negative] [name ]"; static inline void CheckEven(int& N, char dir) { @@ -82,12 +86,24 @@ DataSet_GridFlt* GridAction::GridInit(const char* callingRoutine, ArgList& argIn // For backwards compat., enforce even grid spacing. CheckEven( nx, 'X' ); CheckEven( ny, 'Y' ); CheckEven( nz, 'Z' ); Vec3 gridctr(0.0, 0.0, 0.0); + // Check if we want to specifically re-center the grid during DoAction + gridMoveType_ = NO_OFFSET; if (argIn.hasKey("gridcenter")) { double cx = argIn.getNextDouble(0.0); double cy = argIn.getNextDouble(0.0); double cz = argIn.getNextDouble(0.0); gridctr.SetVec(cx, cy, cz); specifiedCenter = true; + } else if (argIn.hasKey("boxcenter")) { + specifiedCenter = true; + gridMoveType_ = BOX_CENTER; + } else { + std::string maskCenterArg = argIn.GetStringKey("maskcenter"); + if (!maskCenterArg.empty()) { + specifiedCenter = true; + gridMoveType_ = MASK_CENTER; + if (centerMask_.SetMaskString( maskCenterArg )) return 0; + } } Grid = (DataSet_GridFlt*)DSL.AddSet( DataSet::GRID_FLT, argIn.GetStringKey("name"), "GRID" ); if (Grid == 0) return 0; diff --git a/src/cpptrajdepend b/src/cpptrajdepend index f2570a48b4..1b953d4435 100644 --- a/src/cpptrajdepend +++ b/src/cpptrajdepend @@ -316,7 +316,7 @@ ForLoop_mask.o : ForLoop_mask.cpp Action.h ActionList.h ActionState.h Analysis.h ForLoop_overSets.o : ForLoop_overSets.cpp Action.h ActionList.h ActionState.h Analysis.h AnalysisList.h AnalysisState.h ArgList.h AssociatedData.h Atom.h AtomMask.h AtomType.h BaseIOtype.h Box.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajState.h CpptrajStdio.h DataFile.h DataFileList.h DataSet.h DataSetList.h DataSet_Coords.h DataSet_Coords_REF.h Dimension.h DispatchObject.h EnsembleIn.h EnsembleOutList.h FileIO.h FileName.h FileTypes.h ForLoop.h ForLoop_overSets.h Frame.h FramePtrArray.h InputTrajCommon.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h ReplicaInfo.h Residue.h Segment.h SymbolExporting.h TextFormat.h Timer.h Topology.h TrajFrameCounter.h Trajin.h TrajinList.h TrajoutList.h TypeNameHolder.h Unit.h Vec3.h Frame.o : Frame.cpp Atom.h AtomMask.h Box.h Constants.h CoordinateInfo.h CpptrajStdio.h Frame.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h Unit.h Vec3.h GIST_PME.o : GIST_PME.cpp Atom.h AtomMask.h AtomType.h Box.h Constants.h CoordinateInfo.h CpptrajStdio.h EnergyKernel_Adjust.h EnergyKernel_Nonbond.h Ewald.h Ewald_ParticleMesh.h ExclusionArray.h FileName.h Frame.h GIST_PME.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h PairList.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h Segment.h SplineFxnTable.h SymbolExporting.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h helpme_standalone.h -GridAction.o : GridAction.cpp ArgList.h ArrayIterator.h AssociatedData.h Atom.h AtomMask.h AtomType.h Box.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataSet.h DataSetList.h DataSet_3D.h DataSet_Coords.h DataSet_Coords_REF.h DataSet_GridFlt.h Dimension.h FileIO.h FileName.h Frame.h Grid.h GridAction.h GridBin.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h TextFormat.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h +GridAction.o : GridAction.cpp ArgList.h ArrayIterator.h AssociatedData.h Atom.h AtomMask.h AtomType.h Box.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataSet.h DataSetList.h DataSet_3D.h DataSet_Coords.h DataSet_Coords_REF.h DataSet_GridFlt.h Dimension.h FileIO.h FileName.h Frame.h Grid.h GridAction.h GridBin.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h Segment.h StringRoutines.h SymbolExporting.h TextFormat.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h HistBin.o : HistBin.cpp Constants.h CpptrajStdio.h Dimension.h HistBin.h Hungarian.o : Hungarian.cpp ArrayIterator.h Constants.h CpptrajStdio.h Hungarian.h Matrix.h ImageRoutines.o : ImageRoutines.cpp Atom.h AtomMask.h Box.h CoordinateInfo.h CpptrajStdio.h DistRoutines.h Frame.h ImageOption.h ImageRoutines.h ImageTypes.h Image_List.h Image_List_Mask.h Image_List_Pair.h Image_List_Pair_CoM.h Image_List_Pair_First.h Image_List_Pair_Geom.h Image_List_Unit.h Image_List_Unit_CoM.h Image_List_Unit_First.h Image_List_Unit_Geom.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h Unit.h Vec3.h From 32dfbfebc5bb7358ebfa9529f1124bc7e9b09b18 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 25 Jun 2021 13:39:07 -0400 Subject: [PATCH 25/79] Ensure mask is set up. Add MoveGrid calls to GridAction actions --- src/Action_Dipole.cpp | 3 +++ src/Action_Grid.cpp | 2 ++ src/Action_GridFreeEnergy.cpp | 2 ++ src/GridAction.cpp | 4 +++- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Action_Dipole.cpp b/src/Action_Dipole.cpp index 4fdf5f05e8..a83f06fbd0 100644 --- a/src/Action_Dipole.cpp +++ b/src/Action_Dipole.cpp @@ -104,6 +104,9 @@ Action::RetType Action_Dipole::Setup(ActionSetup& setup) { Action::RetType Action_Dipole::DoAction(int frameNum, ActionFrame& frm) { Vec3 cXYZ, dipolar_vector, COM; + // Move grid if necessary + MoveGrid( frm.Frm(), *grid_ ); + // Set up center to origin or box center if (GridOffsetType() == GridAction::BOX_CENTER) cXYZ = frm.Frm().BoxCrd().Center(); diff --git a/src/Action_Grid.cpp b/src/Action_Grid.cpp index b11ace4a5b..253a289766 100644 --- a/src/Action_Grid.cpp +++ b/src/Action_Grid.cpp @@ -128,6 +128,8 @@ Action::RetType Action_Grid::Setup(ActionSetup& setup) { // Action_Grid::DoAction() Action::RetType Action_Grid::DoAction(int frameNum, ActionFrame& frm) { + // Move grid if necessary + MoveGrid( frm.Frm(), *grid_ ); if (useMaskArray_) { Vec3 offset(0.0); if (GridOffsetType() == BOX_CENTER) diff --git a/src/Action_GridFreeEnergy.cpp b/src/Action_GridFreeEnergy.cpp index 5f1e14e485..b5d4a6e15c 100644 --- a/src/Action_GridFreeEnergy.cpp +++ b/src/Action_GridFreeEnergy.cpp @@ -82,6 +82,8 @@ Action::RetType Action_GridFreeEnergy::Setup(ActionSetup& setup) { // Action_GridFreeEnergy::action() Action::RetType Action_GridFreeEnergy::DoAction(int frameNum, ActionFrame& frm) { + // Move grid if necessary + MoveGrid( frm.Frm(), *grid_ ); GridFrame( frm.Frm(), mask_, *grid_ ); return Action::OK; } diff --git a/src/GridAction.cpp b/src/GridAction.cpp index 467cf9e3c3..227206634b 100644 --- a/src/GridAction.cpp +++ b/src/GridAction.cpp @@ -177,7 +177,9 @@ int GridAction::GridSetup(Topology const& currentParm, CoordinateInfo const& cIn mprintf("Warning: No offset will be used.\n"); gridOffsetType_ = NO_OFFSET; // TODO Error? } - } else if (gridOffsetType_ == MASK_CENTER) { + } + // Set up mask + if (centerMask_.MaskStringSet()) { if ( currentParm.SetupIntegerMask( centerMask_ ) ) return 1; centerMask_.MaskInfo(); if ( centerMask_.None() ) { From 5561d1d411986c15045fb8e5a16be5d3dba97f11 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 25 Jun 2021 14:02:50 -0400 Subject: [PATCH 26/79] Add info on grid move type --- src/GridAction.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/GridAction.cpp b/src/GridAction.cpp index 227206634b..e1bbeaaa27 100644 --- a/src/GridAction.cpp +++ b/src/GridAction.cpp @@ -160,6 +160,11 @@ void GridAction::GridInfo(DataSet_GridFlt const& grid) { else if (gridOffsetType_ == MASK_CENTER) mprintf("\tOffset for points is center of atoms in mask [%s]\n", centerMask_.MaskString()); + if (gridMoveType_ == BOX_CENTER) + mprintf("\tGrid will be kept centered at the box center.\n"); + else + mprintf("\tGrid will be kept centered on atoms in mask [%s]\n", + centerMask_.MaskString()); if (increment_ > 0) mprintf("\tCalculating positive density.\n"); else From 83469fd5c36054205c0c3d6515e0e4132a54dd94 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 28 Jun 2021 13:25:44 -0400 Subject: [PATCH 27/79] Create GridBin source file --- src/GridBin.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++ src/GridBin.h | 66 ++--------------------------------------------- src/cpptrajdepend | 1 + src/cpptrajfiles | 1 + 4 files changed, 67 insertions(+), 64 deletions(-) create mode 100644 src/GridBin.cpp diff --git a/src/GridBin.cpp b/src/GridBin.cpp new file mode 100644 index 0000000000..59e5667668 --- /dev/null +++ b/src/GridBin.cpp @@ -0,0 +1,63 @@ +#include "GridBin.h" + +/** Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. */ +void GridBin::Setup_O_D(size_t nx, size_t ny, size_t nz, + Vec3 const& oxyzIn, Vec3 const& dxyz) +{ + OXYZ_ = oxyzIn; + dx_ = dxyz[0]; + dy_ = dxyz[1]; + dz_ = dxyz[2]; + mx_ = OXYZ_[0] + ((double)nx * dx_); + my_ = OXYZ_[1] + ((double)ny * dy_); + mz_ = OXYZ_[2] + ((double)nz * dz_); + nx_ = (double)nx; + ny_ = (double)ny; + nz_ = (double)nz; + voxelvolume_ = dx_ * dy_ * dz_; + // Set orthogonal unit cell vectors. TODO should these be w.r.t. the offset? + double ucell[9]; + ucell[0] = (double)nx * dx_; + ucell[1] = 0; + ucell[2] = 0; + + ucell[3] = 0; + ucell[4] = (double)ny * dy_; + ucell[5] = 0; + + ucell[6] = 0; + ucell[7] = 0; + ucell[8] = (double)nz * dz_; + + box_.SetupFromUcell(ucell); + box_.PrintDebug("GridBin::Setup_O_D"); + SetupInternalPointers(); +} + +/** Set up for grid with given bins, origin, and box.*/ +void GridBin::Setup_O_Box(size_t nxIn, size_t nyIn, size_t nzIn, + Vec3 const& oxyzIn, Box const& boxIn) +{ + nx_ = (double)nxIn; + ny_ = (double)nyIn; + nz_ = (double)nzIn; + OXYZ_ = oxyzIn; + box_ = boxIn; + box_.PrintDebug("GridBin::Setup_O_Box"); + // Get the 3 individual unit cell vector lengths + double l_Avec = box_.UnitCell().Row1().Length(); + double l_Bvec = box_.UnitCell().Row2().Length(); + double l_Cvec = box_.UnitCell().Row3().Length(); + // Get spacing from vector length over bins + dx_ = l_Avec / nx_; + dy_ = l_Bvec / ny_; + dz_ = l_Cvec / nz_; + // Get max from origin plus vector length + mx_ = OXYZ_[0] + l_Avec; + my_ = OXYZ_[1] + l_Bvec; + mz_ = OXYZ_[2] + l_Cvec; + // Get voxel volume from total grid volume over number of bins. + voxelvolume_ = boxIn.CellVolume() / (nx_ * ny_ * nz_); + SetupInternalPointers(); +} + diff --git a/src/GridBin.h b/src/GridBin.h index 6e8163a3fd..a6cc360ecf 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -40,9 +40,9 @@ class GridBin { // Set up routines. inline void SetOrigin(Vec3 const&); /// Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. - inline void Setup_O_D(size_t, size_t, size_t, Vec3 const&, Vec3 const&); + void Setup_O_D(size_t, size_t, size_t, Vec3 const&, Vec3 const&); /// Set up for grid with given bins, origin, and box. - inline void Setup_O_Box(size_t, size_t, size_t, Vec3 const&, Box const&); + void Setup_O_Box(size_t, size_t, size_t, Vec3 const&, Box const&); private: inline bool Calc_ortho(double, double, double, size_t&, size_t&, size_t&) const; inline bool Calc_nonortho(double, double, double, size_t&, size_t&, size_t&) const; @@ -231,66 +231,4 @@ void GridBin::SetOrigin(Vec3 const& newOxyz) { } } -/** Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. */ -void GridBin::Setup_O_D(size_t nx, size_t ny, size_t nz, - Vec3 const& oxyzIn, Vec3 const& dxyz) -{ - OXYZ_ = oxyzIn; - dx_ = dxyz[0]; - dy_ = dxyz[1]; - dz_ = dxyz[2]; - mx_ = OXYZ_[0] + ((double)nx * dx_); - my_ = OXYZ_[1] + ((double)ny * dy_); - mz_ = OXYZ_[2] + ((double)nz * dz_); - nx_ = (double)nx; - ny_ = (double)ny; - nz_ = (double)nz; - voxelvolume_ = dx_ * dy_ * dz_; - // Set orthogonal unit cell vectors. TODO should these be w.r.t. the offset? - double ucell[9]; - ucell[0] = (double)nx * dx_; - ucell[1] = 0; - ucell[2] = 0; - - ucell[3] = 0; - ucell[4] = (double)ny * dy_; - ucell[5] = 0; - - ucell[6] = 0; - ucell[7] = 0; - ucell[8] = (double)nz * dz_; - - box_.SetupFromUcell(ucell); - box_.PrintDebug("GridBin::Setup_O_D"); - SetupInternalPointers(); -} - - -/** Set up for grid with given bins, origin, and box.*/ -void GridBin::Setup_O_Box(size_t nxIn, size_t nyIn, size_t nzIn, - Vec3 const& oxyzIn, Box const& boxIn) -{ - nx_ = (double)nxIn; - ny_ = (double)nyIn; - nz_ = (double)nzIn; - OXYZ_ = oxyzIn; - box_ = boxIn; - box_.PrintDebug("GridBin::Setup_O_Box"); - // Get the 3 individual unit cell vector lengths - double l_Avec = box_.UnitCell().Row1().Length(); - double l_Bvec = box_.UnitCell().Row2().Length(); - double l_Cvec = box_.UnitCell().Row3().Length(); - // Get spacing from vector length over bins - dx_ = l_Avec / nx_; - dy_ = l_Bvec / ny_; - dz_ = l_Cvec / nz_; - // Get max from origin plus vector length - mx_ = OXYZ_[0] + l_Avec; - my_ = OXYZ_[1] + l_Bvec; - mz_ = OXYZ_[2] + l_Cvec; - // Get voxel volume from total grid volume over number of bins. - voxelvolume_ = boxIn.CellVolume() / (nx_ * ny_ * nz_); - SetupInternalPointers(); -} - #endif diff --git a/src/cpptrajdepend b/src/cpptrajdepend index 1b953d4435..08ad8f23a1 100644 --- a/src/cpptrajdepend +++ b/src/cpptrajdepend @@ -317,6 +317,7 @@ ForLoop_overSets.o : ForLoop_overSets.cpp Action.h ActionList.h ActionState.h An Frame.o : Frame.cpp Atom.h AtomMask.h Box.h Constants.h CoordinateInfo.h CpptrajStdio.h Frame.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h Unit.h Vec3.h GIST_PME.o : GIST_PME.cpp Atom.h AtomMask.h AtomType.h Box.h Constants.h CoordinateInfo.h CpptrajStdio.h EnergyKernel_Adjust.h EnergyKernel_Nonbond.h Ewald.h Ewald_ParticleMesh.h ExclusionArray.h FileName.h Frame.h GIST_PME.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h PairList.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h Segment.h SplineFxnTable.h SymbolExporting.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h helpme_standalone.h GridAction.o : GridAction.cpp ArgList.h ArrayIterator.h AssociatedData.h Atom.h AtomMask.h AtomType.h Box.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataSet.h DataSetList.h DataSet_3D.h DataSet_Coords.h DataSet_Coords_REF.h DataSet_GridFlt.h Dimension.h FileIO.h FileName.h Frame.h Grid.h GridAction.h GridBin.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h Segment.h StringRoutines.h SymbolExporting.h TextFormat.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h +GridBin.o : GridBin.cpp Box.h GridBin.h Matrix_3x3.h Parallel.h Vec3.h HistBin.o : HistBin.cpp Constants.h CpptrajStdio.h Dimension.h HistBin.h Hungarian.o : Hungarian.cpp ArrayIterator.h Constants.h CpptrajStdio.h Hungarian.h Matrix.h ImageRoutines.o : ImageRoutines.cpp Atom.h AtomMask.h Box.h CoordinateInfo.h CpptrajStdio.h DistRoutines.h Frame.h ImageOption.h ImageRoutines.h ImageTypes.h Image_List.h Image_List_Mask.h Image_List_Pair.h Image_List_Pair_CoM.h Image_List_Pair_First.h Image_List_Pair_Geom.h Image_List_Unit.h Image_List_Unit_CoM.h Image_List_Unit_First.h Image_List_Unit_Geom.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h Unit.h Vec3.h diff --git a/src/cpptrajfiles b/src/cpptrajfiles index d2c4f63969..609fa9d1a4 100644 --- a/src/cpptrajfiles +++ b/src/cpptrajfiles @@ -316,6 +316,7 @@ COMMON_SOURCES= \ Frame.cpp \ GIST_PME.cpp \ GridAction.cpp \ + GridBin.cpp \ HistBin.cpp \ Hungarian.cpp \ ImageRoutines.cpp \ From 80887aecfdfde5a9a8733a98866650fc64899300 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 28 Jun 2021 13:31:18 -0400 Subject: [PATCH 28/79] Fix max determination --- src/GridBin.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/GridBin.h b/src/GridBin.h index a6cc360ecf..fe2b24607c 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -221,13 +221,12 @@ void GridBin::SetOrigin(Vec3 const& newOxyz) { my_ = OXYZ_[1] + (ny_ * dy_); mz_ = OXYZ_[2] + (nz_ * dz_); } else { - double l_Avec = box_.UnitCell().Row1().Length(); - double l_Bvec = box_.UnitCell().Row2().Length(); - double l_Cvec = box_.UnitCell().Row3().Length(); - // Get max from origin plus vector length - mx_ = OXYZ_[0] + l_Avec; - my_ = OXYZ_[1] + l_Bvec; - mz_ = OXYZ_[2] + l_Cvec; + // Get vector pointing from coord origin to max grid + // TODO is this necessary? mx etc not used unless X aligned... + Vec3 maxVec = box_.UnitCell().TransposeMult( Vec3(1.0, 1.0, 1.0) ); + mx_ = OXYZ_[0] + maxVec[0]; + my_ = OXYZ_[1] + maxVec[1]; + mz_ = OXYZ_[2] + maxVec[2]; } } From d9b83c317097983087f434cea1031ad0e64abc1f Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 28 Jun 2021 13:36:50 -0400 Subject: [PATCH 29/79] Add function to set new origin from center --- src/GridBin.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/GridBin.h b/src/GridBin.h index fe2b24607c..8538f31043 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -39,6 +39,7 @@ class GridBin { // Set up routines. inline void SetOrigin(Vec3 const&); + inline void SetOriginFromCenter(Vec3 const&); /// Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. void Setup_O_D(size_t, size_t, size_t, Vec3 const&, Vec3 const&); /// Set up for grid with given bins, origin, and box. @@ -230,4 +231,14 @@ void GridBin::SetOrigin(Vec3 const& newOxyz) { } } +/** Set new origin for grid based on location of center, update max. */ +void GridBin::SetOriginFromCenter(Vec3 const& newCxyz) { + // Get vector pointing from coord origin to center + Vec3 centerVec = box_.UnitCell().TransposeMult( Vec3(0.5, 0.5, 0.5) ); + OXYZ_ = newCxyz - centerVec; + mx_ = newCxyz[0] + centerVec[0]; + my_ = newCxyz[1] + centerVec[1]; + mz_ = newCxyz[2] + centerVec[2]; +} + #endif From 45d9eb54fce41512462984b5f5b42b8a63a46c12 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 10:07:20 -0400 Subject: [PATCH 30/79] Add X-aligned ortho case --- src/GridBin.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/GridBin.h b/src/GridBin.h index 8538f31043..14037508d4 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -234,7 +234,12 @@ void GridBin::SetOrigin(Vec3 const& newOxyz) { /** Set new origin for grid based on location of center, update max. */ void GridBin::SetOriginFromCenter(Vec3 const& newCxyz) { // Get vector pointing from coord origin to center - Vec3 centerVec = box_.UnitCell().TransposeMult( Vec3(0.5, 0.5, 0.5) ); + Vec3 centerVec; + if (box_.Is_X_Aligned_Ortho()) { + centerVec = Vec3(box_.Param(Box::X)/2.0, box_.Param(Box::Y)/2.0, box_.Param(Box::Z)/2.0); + } else { + centerVec = box_.UnitCell().TransposeMult( Vec3(0.5, 0.5, 0.5) ); + } OXYZ_ = newCxyz - centerVec; mx_ = newCxyz[0] + centerVec[0]; my_ = newCxyz[1] + centerVec[1]; From fc581a26748776765dfeb26e85af9776ceca9311 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 10:27:28 -0400 Subject: [PATCH 31/79] Start moving allocation logic from DataSet_3D to GridBin --- src/GridBin.cpp | 86 ++++++++++++++++++++++++++----------------------- src/GridBin.h | 10 ++++-- 2 files changed, 54 insertions(+), 42 deletions(-) diff --git a/src/GridBin.cpp b/src/GridBin.cpp index 59e5667668..2dd56a6d12 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -1,49 +1,34 @@ #include "GridBin.h" -/** Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. */ -void GridBin::Setup_O_D(size_t nx, size_t ny, size_t nz, - Vec3 const& oxyzIn, Vec3 const& dxyz) +/** Set voxel volume from total grid volume over number of bins. */ +void GridBin::set_voxel_volume() { + voxelvolume_ = box_.CellVolume() / (nx_ * ny_ * nz_); +} + +/** Put given grid sizes into an array. */ +static inline GridBin::SizeArray getGridSizes(size_t nx, size_t ny, size_t nz) { - OXYZ_ = oxyzIn; - dx_ = dxyz[0]; - dy_ = dxyz[1]; - dz_ = dxyz[2]; - mx_ = OXYZ_[0] + ((double)nx * dx_); - my_ = OXYZ_[1] + ((double)ny * dy_); - mz_ = OXYZ_[2] + ((double)nz * dz_); - nx_ = (double)nx; - ny_ = (double)ny; - nz_ = (double)nz; - voxelvolume_ = dx_ * dy_ * dz_; - // Set orthogonal unit cell vectors. TODO should these be w.r.t. the offset? - double ucell[9]; - ucell[0] = (double)nx * dx_; - ucell[1] = 0; - ucell[2] = 0; - - ucell[3] = 0; - ucell[4] = (double)ny * dy_; - ucell[5] = 0; - - ucell[6] = 0; - ucell[7] = 0; - ucell[8] = (double)nz * dz_; - - box_.SetupFromUcell(ucell); - box_.PrintDebug("GridBin::Setup_O_D"); - SetupInternalPointers(); + SizeArray gridSizes(3); + gridSizes[0] = nx; + gridSizes[1] = ny; + gridSizes[2] = nz; + return gridSizes; } /** Set up for grid with given bins, origin, and box.*/ -void GridBin::Setup_O_Box(size_t nxIn, size_t nyIn, size_t nzIn, - Vec3 const& oxyzIn, Box const& boxIn) +GridBin::SizeArray GridBin::Setup_Sizes_Origin_Box(size_t nxIn, size_t nyIn, size_t nzIn, + Vec3 const& oxyzIn, Box const& boxIn) { + // Set grid dimensions nx_ = (double)nxIn; ny_ = (double)nyIn; nz_ = (double)nzIn; OXYZ_ = oxyzIn; + // Set grid box and internal pointers based on box. box_ = boxIn; - box_.PrintDebug("GridBin::Setup_O_Box"); + box_.PrintDebug("GridBin::Setup_Sizes_Origin_Box"); + SetupInternalPointers(); + set_voxel_volume(); // Get the 3 individual unit cell vector lengths double l_Avec = box_.UnitCell().Row1().Length(); double l_Bvec = box_.UnitCell().Row2().Length(); @@ -52,12 +37,33 @@ void GridBin::Setup_O_Box(size_t nxIn, size_t nyIn, size_t nzIn, dx_ = l_Avec / nx_; dy_ = l_Bvec / ny_; dz_ = l_Cvec / nz_; - // Get max from origin plus vector length - mx_ = OXYZ_[0] + l_Avec; - my_ = OXYZ_[1] + l_Bvec; - mz_ = OXYZ_[2] + l_Cvec; - // Get voxel volume from total grid volume over number of bins. - voxelvolume_ = boxIn.CellVolume() / (nx_ * ny_ * nz_); + // Set origin and max + SetOrigin( oxyzIn ); + + return getGridSizes(nxIn, nyIn, nzIn); +} + +/** Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. */ +GridBin::SizeArray GridBin::Setup_Sizes_Origin_Spacing(size_t nx, size_t ny, size_t nz, + Vec3 const& oxyzIn, Vec3 const& dxyz) +{ + // Set grid dimensions + nx_ = (double)nx; + ny_ = (double)ny; + nz_ = (double)nz; + // Set grid spacings + dx_ = dxyz[0]; + dy_ = dxyz[1]; + dz_ = dxyz[2]; + // Set grid box and internal pointers based on box. + box_.SetupFromXyzAbg( nx_ * dx_, ny_ * dy_, nz_ * dz, 90.0, 90.0, 90.0 ); + box_.PrintDebug("GridBin::Setup_Sizes_Origin_Spacing"); SetupInternalPointers(); + set_voxel_volume(); + // Set origin and max + SetOrigin( oxyzIn ); + + return getGridSizes(nx, ny, nz); } + diff --git a/src/GridBin.h b/src/GridBin.h index 14037508d4..a33ac6abb9 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -1,6 +1,7 @@ #ifndef INC_GRIDBIN_H #define INC_GRIDBIN_H #include // size_t +#include #include "Box.h" //#inc lude "CpptrajStdio.h" // DEBUG /// Class used to perform binning on/get voxel coords of 3D grids. @@ -38,12 +39,16 @@ class GridBin { inline double DZ() const { return dz_; } // Set up routines. + /// Set grid origin inline void SetOrigin(Vec3 const&); + /// Set grid origin via given center point. inline void SetOriginFromCenter(Vec3 const&); + /// Type for returning grid dimensions in terms of bins from setup routines + typedef std::vector SizeArray; /// Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. - void Setup_O_D(size_t, size_t, size_t, Vec3 const&, Vec3 const&); + SizeArray Setup_Sizes_Origin_Spacing(size_t, size_t, size_t, Vec3 const&, Vec3 const&); /// Set up for grid with given bins, origin, and box. - void Setup_O_Box(size_t, size_t, size_t, Vec3 const&, Box const&); + SizeArray Setup_O_Box(size_t, size_t, size_t, Vec3 const&, Box const&); private: inline bool Calc_ortho(double, double, double, size_t&, size_t&, size_t&) const; inline bool Calc_nonortho(double, double, double, size_t&, size_t&, size_t&) const; @@ -54,6 +59,7 @@ class GridBin { inline Vec3 Center_ortho(long int, long int, long int) const; inline Vec3 Center_nonortho(long int, long int, long int) const; inline void SetupInternalPointers(); + void set_voxel_volume(); Vec3 OXYZ_; ///< Grid origin. double dx_, dy_, dz_; ///< Grid spacing (Ang., Cartesian, orthogonal). From 6305a50f6216dff29160ec5cbe2e492c0c85f8fd Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 10:32:18 -0400 Subject: [PATCH 32/79] Clean up, add sizes/center/spacing --- src/GridBin.cpp | 27 +++++++++++++++++++++++++-- src/GridBin.h | 6 ++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/GridBin.cpp b/src/GridBin.cpp index 2dd56a6d12..e2cbb902be 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -8,7 +8,7 @@ void GridBin::set_voxel_volume() { /** Put given grid sizes into an array. */ static inline GridBin::SizeArray getGridSizes(size_t nx, size_t ny, size_t nz) { - SizeArray gridSizes(3); + GridBin::SizeArray gridSizes(3); gridSizes[0] = nx; gridSizes[1] = ny; gridSizes[2] = nz; @@ -56,7 +56,7 @@ GridBin::SizeArray GridBin::Setup_Sizes_Origin_Spacing(size_t nx, size_t ny, siz dy_ = dxyz[1]; dz_ = dxyz[2]; // Set grid box and internal pointers based on box. - box_.SetupFromXyzAbg( nx_ * dx_, ny_ * dy_, nz_ * dz, 90.0, 90.0, 90.0 ); + box_.SetupFromXyzAbg( nx_ * dx_, ny_ * dy_, nz_ * dz_, 90.0, 90.0, 90.0 ); box_.PrintDebug("GridBin::Setup_Sizes_Origin_Spacing"); SetupInternalPointers(); set_voxel_volume(); @@ -66,4 +66,27 @@ GridBin::SizeArray GridBin::Setup_Sizes_Origin_Spacing(size_t nx, size_t ny, siz return getGridSizes(nx, ny, nz); } +/** Set up for orthogonal X-aligned grid with given center and spacing; calculate maximum. */ +GridBin::SizeArray GridBin::Setup_Sizes_Center_Spacing(size_t nx, size_t ny, size_t nz, + Vec3 const& cxyzIn, Vec3 const& dxyz) +{ + // Set grid dimensions + nx_ = (double)nx; + ny_ = (double)ny; + nz_ = (double)nz; + // Set grid spacings + dx_ = dxyz[0]; + dy_ = dxyz[1]; + dz_ = dxyz[2]; + // Set grid box and internal pointers based on box. + box_.SetupFromXyzAbg( nx_ * dx_, ny_ * dy_, nz_ * dz_, 90.0, 90.0, 90.0 ); + box_.PrintDebug("GridBin::Setup_Sizes_Center_Spacing"); + SetupInternalPointers(); + set_voxel_volume(); + // Set origin and max + SetOriginFromCenter( cxyzIn ); + + return getGridSizes(nx, ny, nz); +} + diff --git a/src/GridBin.h b/src/GridBin.h index a33ac6abb9..64ca2ed4aa 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -45,10 +45,12 @@ class GridBin { inline void SetOriginFromCenter(Vec3 const&); /// Type for returning grid dimensions in terms of bins from setup routines typedef std::vector SizeArray; + /// Set up for grid with given bins, origin, and box. + SizeArray Setup_Sizes_Origin_Box(size_t, size_t, size_t, Vec3 const&, Box const&); /// Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. SizeArray Setup_Sizes_Origin_Spacing(size_t, size_t, size_t, Vec3 const&, Vec3 const&); - /// Set up for grid with given bins, origin, and box. - SizeArray Setup_O_Box(size_t, size_t, size_t, Vec3 const&, Box const&); + /// Set up for orthogonal X-aligned grid with given center and spacing; calculate maximum. + SizeArray Setup_Sizes_Center_Spacing(size_t, size_t, size_t, Vec3 const&, Vec3 const&); private: inline bool Calc_ortho(double, double, double, size_t&, size_t&, size_t&) const; inline bool Calc_nonortho(double, double, double, size_t&, size_t&, size_t&) const; From 8087866a85d2b217b0284535dda34905f52d10d8 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 10:37:24 -0400 Subject: [PATCH 33/79] Add routine with lengths, center, spacing --- src/GridBin.cpp | 12 +++++++++++- src/GridBin.h | 6 ++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/GridBin.cpp b/src/GridBin.cpp index e2cbb902be..b2ce1e4615 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -1,4 +1,5 @@ #include "GridBin.h" +#include // ceil /** Set voxel volume from total grid volume over number of bins. */ void GridBin::set_voxel_volume() { @@ -89,4 +90,13 @@ GridBin::SizeArray GridBin::Setup_Sizes_Center_Spacing(size_t nx, size_t ny, siz return getGridSizes(nx, ny, nz); } - +/** Set up for orthogonal X-aligned grid with given lengths, center and spacing. */ +GridBin::SizeArray GridBin::Setup_Lengths_Center_Spacing(Vec3 const& lengths, Vec3 const& center, + Vec3 const& dxyz) +{ + // Calculate bin counts + size_t nx = (size_t)ceil(lengths[0] / dxyz[0]); + size_t ny = (size_t)ceil(lengths[1] / dxyz[1]); + size_t nz = (size_t)ceil(lengths[2] / dxyz[2]); + return Setup_Sizes_Center_Spacing(nx, ny, nz, center, dxyz); +} diff --git a/src/GridBin.h b/src/GridBin.h index 64ca2ed4aa..5ec1d11f20 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -47,10 +47,12 @@ class GridBin { typedef std::vector SizeArray; /// Set up for grid with given bins, origin, and box. SizeArray Setup_Sizes_Origin_Box(size_t, size_t, size_t, Vec3 const&, Box const&); - /// Set up for orthogonal X-aligned grid with given origin and spacing; calculate maximum. + /// Set up for orthogonal X-aligned grid with given bins, origin and spacing; calculate maximum. SizeArray Setup_Sizes_Origin_Spacing(size_t, size_t, size_t, Vec3 const&, Vec3 const&); - /// Set up for orthogonal X-aligned grid with given center and spacing; calculate maximum. + /// Set up for orthogonal X-aligned grid with given bins, center and spacing; calculate maximum. SizeArray Setup_Sizes_Center_Spacing(size_t, size_t, size_t, Vec3 const&, Vec3 const&); + /// Set up for orthogonal X-aligned grid with given lengths, center, and spacing. + SizeArray Setup_Lengths_Center_Spacing(Vec3 const&, Vec3 const&, Vec3 const&); private: inline bool Calc_ortho(double, double, double, size_t&, size_t&, size_t&) const; inline bool Calc_nonortho(double, double, double, size_t&, size_t&, size_t&) const; From 247f7be1f29446ff8355f99ec444bc1f4b9aa2a8 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 10:47:06 -0400 Subject: [PATCH 34/79] Use the new GridBin setup routines --- src/DataSet_3D.cpp | 25 ++++++++++++++++--------- src/DataSet_3D.h | 6 +++--- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/DataSet_3D.cpp b/src/DataSet_3D.cpp index 6cb26b9056..c864ef0e0a 100644 --- a/src/DataSet_3D.cpp +++ b/src/DataSet_3D.cpp @@ -32,7 +32,7 @@ int DataSet_3D::Allocate_N_O_Box(size_t nx, size_t ny, size_t nz, return 1; } // Set origin and unit cell params. - gridBin_.Setup_O_Box(nx, ny, nz, oxyz, boxIn); + gridBin_.Setup_Sizes_Origin_Box(nx, ny, nz, oxyz, boxIn); return Allocate3D(nx, ny, nz); } @@ -45,7 +45,7 @@ int DataSet_3D::Allocate_N_O_D(size_t nx, size_t ny, size_t nz, return 1; } // Set origin and spacing, calculate maximum (for binning). - gridBin_.Setup_O_D(nx, ny, nz, oxyz, dxyz); + gridBin_.Setup_Sizes_Origin_Spacing(nx, ny, nz, oxyz, dxyz); return Allocate3D(nx, ny, nz); } @@ -53,6 +53,7 @@ int DataSet_3D::Allocate_N_O_D(size_t nx, size_t ny, size_t nz, /** For even-spaced grids, origin is center - (N/2)*spacing. * For odd-spaced grids, origin is center - ((N-1/2)*spacing)+half_spacing */ +/* static double Calc_Origin(size_t N, double D) { size_t odd = N % 2; size_t half = (N - odd) / 2; @@ -61,8 +62,10 @@ static double Calc_Origin(size_t N, double D) { else return -((double)half * D); } +*/ /** \return Origin coords calculated from given center coords, spacings, and # of bins. */ +/* Vec3 DataSet_3D::calcOriginFromCenter(Vec3 const& cxyz, double dx, double dy, double dz, size_t nx, size_t ny, size_t nz) @@ -70,16 +73,18 @@ Vec3 DataSet_3D::calcOriginFromCenter(Vec3 const& cxyz, return Vec3( cxyz[0] + Calc_Origin(nx, dx), cxyz[1] + Calc_Origin(ny, dy), cxyz[2] + Calc_Origin(nz, dz) ); -} +}*/ // DataSet_3D::Allocate_N_C_D() int DataSet_3D::Allocate_N_C_D(size_t nx, size_t ny, size_t nz, Vec3 const& cxyz, Vec3 const& dxyz) { // Calculate origin from center coordinates. - return Allocate_N_O_D(nx, ny, nz, + gridBin_.Setup_Sizes_Center_Spacing(nx, ny, nz, cxyz, dxyz); + return Allocate3D(nx, ny, nz); +/* return Allocate_N_O_D(nx, ny, nz, calcOriginFromCenter(cxyz, dxyz[0], dxyz[1], dxyz[2], nx, ny, nz), - dxyz); + dxyz);*/ /* Vec3 oxyz( cxyz[0] + Calc_Origin(nx, dxyz[0]), cxyz[1] + Calc_Origin(ny, dxyz[1]), @@ -91,19 +96,21 @@ int DataSet_3D::Allocate_N_C_D(size_t nx, size_t ny, size_t nz, int DataSet_3D::Allocate_X_C_D(Vec3 const& sizes, Vec3 const& center, Vec3 const& dxyz) { // Calculate bin counts - size_t nx = (size_t)ceil(sizes[0] / dxyz[0]); + /*size_t nx = (size_t)ceil(sizes[0] / dxyz[0]); size_t ny = (size_t)ceil(sizes[1] / dxyz[1]); size_t nz = (size_t)ceil(sizes[2] / dxyz[2]); - return Allocate_N_C_D( nx, ny, nz, center, dxyz ); + return Allocate_N_C_D( nx, ny, nz, center, dxyz );*/ + GridBin::SizeArray gridSizes = gridBin_.Setup_Lengths_Center_Spacing(sizes, center, dxyz); + return Allocate3D(gridSizes[0], gridSizes[1], gridSizes[2]); } /** Set the center of the grid to given coords via moving the grid origin. */ -void DataSet_3D::SetGridCenter(Vec3 const& cxyz) { +/*void DataSet_3D::SetGridCenter(Vec3 const& cxyz) { gridBin_.SetOrigin( calcOriginFromCenter(cxyz, gridBin_.DX(), gridBin_.DY(), gridBin_.DZ(), NX(), NY(), NZ()) ); -} +}*/ // DataSet_3D::GridInfo() void DataSet_3D::GridInfo() const { diff --git a/src/DataSet_3D.h b/src/DataSet_3D.h index feedd50e92..4638af99d3 100644 --- a/src/DataSet_3D.h +++ b/src/DataSet_3D.h @@ -64,19 +64,19 @@ class DataSet_3D : public DataSet { /// Set up grid from dims, origin, and box. int Allocate_N_O_Box(size_t,size_t,size_t, Vec3 const&, Box const&); /// Move grid center - void SetGridCenter(Vec3 const&); + void SetGridCenter(Vec3 const& cxyz) { gridBin_.SetOriginFromCenter( cxyz); } /// Print grid info. void GridInfo() const; // ------------------------------------------- GridBin const& Bin() const { return gridBin_; } private: /// Check if grid dimension is even; if not, increment it by 1. - static void CheckEven(size_t&, char); + //static void CheckEven(size_t&, char); /// Set up grid for given # x, y, and z points. // TODO: Make public if grids will be used for other than binning. virtual int Allocate3D(size_t, size_t, size_t) = 0; /// \return Origin coords from center, spacing, and sizes - static Vec3 calcOriginFromCenter(Vec3 const&, double, double, double, size_t, size_t, size_t); + //static Vec3 calcOriginFromCenter(Vec3 const&, double, double, double, size_t, size_t, size_t); GridBin gridBin_; ///< Used to calculate bins/coords depending on grid type. }; From da6554c8eb9d77a9e76e35c90d215c610f032d54 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 11:05:00 -0400 Subject: [PATCH 35/79] Add separate debug routine --- src/DataSet_3D.cpp | 4 ++++ src/GridBin.cpp | 15 ++++++++++++--- src/GridBin.h | 4 +++- src/cpptrajdepend | 2 +- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/DataSet_3D.cpp b/src/DataSet_3D.cpp index c864ef0e0a..7d01fa4bb8 100644 --- a/src/DataSet_3D.cpp +++ b/src/DataSet_3D.cpp @@ -33,6 +33,7 @@ int DataSet_3D::Allocate_N_O_Box(size_t nx, size_t ny, size_t nz, } // Set origin and unit cell params. gridBin_.Setup_Sizes_Origin_Box(nx, ny, nz, oxyz, boxIn); + gridBin_.PrintDebug("Allocate_N_O_Box"); return Allocate3D(nx, ny, nz); } @@ -46,6 +47,7 @@ int DataSet_3D::Allocate_N_O_D(size_t nx, size_t ny, size_t nz, } // Set origin and spacing, calculate maximum (for binning). gridBin_.Setup_Sizes_Origin_Spacing(nx, ny, nz, oxyz, dxyz); + gridBin_.PrintDebug("Allocate_N_O_D"); return Allocate3D(nx, ny, nz); } @@ -81,6 +83,7 @@ int DataSet_3D::Allocate_N_C_D(size_t nx, size_t ny, size_t nz, { // Calculate origin from center coordinates. gridBin_.Setup_Sizes_Center_Spacing(nx, ny, nz, cxyz, dxyz); + gridBin_.PrintDebug("Allocate_N_C_D"); return Allocate3D(nx, ny, nz); /* return Allocate_N_O_D(nx, ny, nz, calcOriginFromCenter(cxyz, dxyz[0], dxyz[1], dxyz[2], nx, ny, nz), @@ -101,6 +104,7 @@ int DataSet_3D::Allocate_X_C_D(Vec3 const& sizes, Vec3 const& center, Vec3 const size_t nz = (size_t)ceil(sizes[2] / dxyz[2]); return Allocate_N_C_D( nx, ny, nz, center, dxyz );*/ GridBin::SizeArray gridSizes = gridBin_.Setup_Lengths_Center_Spacing(sizes, center, dxyz); + gridBin_.PrintDebug("Allocate_X_C_D"); return Allocate3D(gridSizes[0], gridSizes[1], gridSizes[2]); } diff --git a/src/GridBin.cpp b/src/GridBin.cpp index b2ce1e4615..dbd9f3e1bc 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -1,4 +1,5 @@ #include "GridBin.h" +#include "CpptrajStdio.h" #include // ceil /** Set voxel volume from total grid volume over number of bins. */ @@ -27,7 +28,6 @@ GridBin::SizeArray GridBin::Setup_Sizes_Origin_Box(size_t nxIn, size_t nyIn, siz OXYZ_ = oxyzIn; // Set grid box and internal pointers based on box. box_ = boxIn; - box_.PrintDebug("GridBin::Setup_Sizes_Origin_Box"); SetupInternalPointers(); set_voxel_volume(); // Get the 3 individual unit cell vector lengths @@ -58,7 +58,6 @@ GridBin::SizeArray GridBin::Setup_Sizes_Origin_Spacing(size_t nx, size_t ny, siz dz_ = dxyz[2]; // Set grid box and internal pointers based on box. box_.SetupFromXyzAbg( nx_ * dx_, ny_ * dy_, nz_ * dz_, 90.0, 90.0, 90.0 ); - box_.PrintDebug("GridBin::Setup_Sizes_Origin_Spacing"); SetupInternalPointers(); set_voxel_volume(); // Set origin and max @@ -81,7 +80,6 @@ GridBin::SizeArray GridBin::Setup_Sizes_Center_Spacing(size_t nx, size_t ny, siz dz_ = dxyz[2]; // Set grid box and internal pointers based on box. box_.SetupFromXyzAbg( nx_ * dx_, ny_ * dy_, nz_ * dz_, 90.0, 90.0, 90.0 ); - box_.PrintDebug("GridBin::Setup_Sizes_Center_Spacing"); SetupInternalPointers(); set_voxel_volume(); // Set origin and max @@ -100,3 +98,14 @@ GridBin::SizeArray GridBin::Setup_Lengths_Center_Spacing(Vec3 const& lengths, Ve size_t nz = (size_t)ceil(lengths[2] / dxyz[2]); return Setup_Sizes_Center_Spacing(nx, ny, nz, center, dxyz); } + +/** Print debug info. */ +void GridBin::PrintDebug(const char* title) const +{ + box_.PrintDebug(title); + mprintf("DEBUG: %s: origin xyz : %12.4f %12.4f %12.4f\n", title, OXYZ_[0], OXYZ_[1], OXYZ_[2]); + mprintf("DEBUG: %s: spacings : %12.4f %12.4f %12.4f\n", title, dx_, dy_, dz_); + mprintf("DEBUG: %s: max xyz : %12.4f %12.4f %12.4f\n", title, mz_, my_, mz_); + mprintf("DEBUG: %s: sizes : %12.0f %12.0f %12.0f\n", title, nx_, ny_, nz_); + mprintf("DEBUG: %s: voxel vol. : %12.4f\n", voxelvolume_); +} diff --git a/src/GridBin.h b/src/GridBin.h index 5ec1d11f20..0c53027a64 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -3,7 +3,6 @@ #include // size_t #include #include "Box.h" -//#inc lude "CpptrajStdio.h" // DEBUG /// Class used to perform binning on/get voxel coords of 3D grids. class GridBin { public: @@ -38,6 +37,9 @@ class GridBin { inline double DY() const { return dy_; } inline double DZ() const { return dz_; } + /// Print debug info + void PrintDebug(const char*) const; + // Set up routines. /// Set grid origin inline void SetOrigin(Vec3 const&); diff --git a/src/cpptrajdepend b/src/cpptrajdepend index 08ad8f23a1..7a1412426b 100644 --- a/src/cpptrajdepend +++ b/src/cpptrajdepend @@ -317,7 +317,7 @@ ForLoop_overSets.o : ForLoop_overSets.cpp Action.h ActionList.h ActionState.h An Frame.o : Frame.cpp Atom.h AtomMask.h Box.h Constants.h CoordinateInfo.h CpptrajStdio.h Frame.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h Unit.h Vec3.h GIST_PME.o : GIST_PME.cpp Atom.h AtomMask.h AtomType.h Box.h Constants.h CoordinateInfo.h CpptrajStdio.h EnergyKernel_Adjust.h EnergyKernel_Nonbond.h Ewald.h Ewald_ParticleMesh.h ExclusionArray.h FileName.h Frame.h GIST_PME.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h PairList.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h Segment.h SplineFxnTable.h SymbolExporting.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h helpme_standalone.h GridAction.o : GridAction.cpp ArgList.h ArrayIterator.h AssociatedData.h Atom.h AtomMask.h AtomType.h Box.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataSet.h DataSetList.h DataSet_3D.h DataSet_Coords.h DataSet_Coords_REF.h DataSet_GridFlt.h Dimension.h FileIO.h FileName.h Frame.h Grid.h GridAction.h GridBin.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterHolders.h ParameterSet.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h Segment.h StringRoutines.h SymbolExporting.h TextFormat.h Timer.h Topology.h TypeNameHolder.h Unit.h Vec3.h -GridBin.o : GridBin.cpp Box.h GridBin.h Matrix_3x3.h Parallel.h Vec3.h +GridBin.o : GridBin.cpp Box.h CpptrajStdio.h GridBin.h Matrix_3x3.h Parallel.h Vec3.h HistBin.o : HistBin.cpp Constants.h CpptrajStdio.h Dimension.h HistBin.h Hungarian.o : Hungarian.cpp ArrayIterator.h Constants.h CpptrajStdio.h Hungarian.h Matrix.h ImageRoutines.o : ImageRoutines.cpp Atom.h AtomMask.h Box.h CoordinateInfo.h CpptrajStdio.h DistRoutines.h Frame.h ImageOption.h ImageRoutines.h ImageTypes.h Image_List.h Image_List_Mask.h Image_List_Pair.h Image_List_Pair_CoM.h Image_List_Pair_First.h Image_List_Pair_Geom.h Image_List_Unit.h Image_List_Unit_CoM.h Image_List_Unit_First.h Image_List_Unit_Geom.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ReplicaDimArray.h Residue.h Segment.h SymbolExporting.h Unit.h Vec3.h From a5ccb2ae95ed8313b38bcf4ee570b00552f141eb Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 11:06:15 -0400 Subject: [PATCH 36/79] Add missing var --- src/GridBin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GridBin.cpp b/src/GridBin.cpp index dbd9f3e1bc..6d4043ce2c 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -107,5 +107,5 @@ void GridBin::PrintDebug(const char* title) const mprintf("DEBUG: %s: spacings : %12.4f %12.4f %12.4f\n", title, dx_, dy_, dz_); mprintf("DEBUG: %s: max xyz : %12.4f %12.4f %12.4f\n", title, mz_, my_, mz_); mprintf("DEBUG: %s: sizes : %12.0f %12.0f %12.0f\n", title, nx_, ny_, nz_); - mprintf("DEBUG: %s: voxel vol. : %12.4f\n", voxelvolume_); + mprintf("DEBUG: %s: voxel vol. : %12.4f\n", title, voxelvolume_); } From f1a7451eecb64bf07df2ec3880eb706a810ae5d0 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 11:20:31 -0400 Subject: [PATCH 37/79] Fix calculation of grid center. Fix info print about centering. --- src/DataSet_3D.cpp | 6 ++---- src/GridAction.cpp | 2 +- src/GridBin.h | 15 ++++++++++++++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/DataSet_3D.cpp b/src/DataSet_3D.cpp index 7d01fa4bb8..138b84eec5 100644 --- a/src/DataSet_3D.cpp +++ b/src/DataSet_3D.cpp @@ -119,15 +119,13 @@ int DataSet_3D::Allocate_X_C_D(Vec3 const& sizes, Vec3 const& center, Vec3 const // DataSet_3D::GridInfo() void DataSet_3D::GridInfo() const { Vec3 const& oxyz = gridBin_.GridOrigin(); + Vec3 cxyz = gridBin_.GridCenter(); mprintf("\t\t-=Grid Dims=- %8s %8s %8s\n", "X", "Y", "Z"); mprintf("\t\t Bins: %8zu %8zu %8zu\n", NX(), NY(), NZ()); mprintf("\t\t Origin: %8g %8g %8g\n", oxyz[0], oxyz[1], oxyz[2]); //if (gridBin_.IsOrthoGrid()) { mprintf("\t\t Spacing: %8g %8g %8g\n", gridBin_.DX(), gridBin_.DY(), gridBin_.DZ()); - mprintf("\t\t Center: %8g %8g %8g\n", - oxyz[0] + (NX()/2)*gridBin_.DX(), - oxyz[1] + (NY()/2)*gridBin_.DY(), - oxyz[2] + (NZ()/2)*gridBin_.DZ()); + mprintf("\t\t Center: %8g %8g %8g\n", cxyz[0], cxyz[1], cxyz[2]); //mprintf("\tGrid max : %8.3f %8.3f %8.3f\n", gridBin_.MX(), gridBin_.MY(), gridBin_.MZ()); //} else { Box const& box = gridBin_.GridBox(); diff --git a/src/GridAction.cpp b/src/GridAction.cpp index e1bbeaaa27..18a57216b2 100644 --- a/src/GridAction.cpp +++ b/src/GridAction.cpp @@ -162,7 +162,7 @@ void GridAction::GridInfo(DataSet_GridFlt const& grid) { centerMask_.MaskString()); if (gridMoveType_ == BOX_CENTER) mprintf("\tGrid will be kept centered at the box center.\n"); - else + else if (gridMoveType_ == MASK_CENTER) mprintf("\tGrid will be kept centered on atoms in mask [%s]\n", centerMask_.MaskString()); if (increment_ > 0) diff --git a/src/GridBin.h b/src/GridBin.h index 0c53027a64..9b05c0dcc1 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -29,8 +29,10 @@ class GridBin { inline double VoxelVolume() const { return voxelvolume_; } /// \return a copy of this GridBin. //virtual GridBin* Copy() const = 0; - /// \return Grid origin. + /// \return Grid origin coordinates. inline Vec3 const& GridOrigin() const { return OXYZ_; } + /// \return Grid center coordinates. + inline Vec3 GridCenter() const; // TODO are these spacing routines needed? inline double DX() const { return dx_; } @@ -258,4 +260,15 @@ void GridBin::SetOriginFromCenter(Vec3 const& newCxyz) { mz_ = newCxyz[2] + centerVec[2]; } +/** \return Grid center coordinates. */ +Vec3 GridBin::GridCenter() const { + // Get vector pointing from coord origin to center + Vec3 centerVec; + if (box_.Is_X_Aligned_Ortho()) { + centerVec = Vec3(box_.Param(Box::X)/2.0, box_.Param(Box::Y)/2.0, box_.Param(Box::Z)/2.0); + } else { + centerVec = box_.UnitCell().TransposeMult( Vec3(0.5, 0.5, 0.5) ); + } + return OXYZ_ + centerVec; +} #endif From 751db98b48b32ce0b0790f8325f898f66c277a46 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 11:23:26 -0400 Subject: [PATCH 38/79] Fix class description --- src/GridBin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GridBin.h b/src/GridBin.h index 9b05c0dcc1..946c269d96 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -3,7 +3,7 @@ #include // size_t #include #include "Box.h" -/// Class used to perform binning on/get voxel coords of 3D grids. +/// Class used to describe 3D grid spatial orientation, as well as perform binning on/get voxel coords. class GridBin { public: /// CONSTRUCTOR From 2b196b6bd5b7db974e59e02d780238f65ee30986 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 11:24:28 -0400 Subject: [PATCH 39/79] Fix up variable descriptions --- src/GridBin.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/GridBin.h b/src/GridBin.h index 946c269d96..61c3378e04 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -69,10 +69,10 @@ class GridBin { inline void SetupInternalPointers(); void set_voxel_volume(); - Vec3 OXYZ_; ///< Grid origin. - double dx_, dy_, dz_; ///< Grid spacing (Ang., Cartesian, orthogonal). - double mx_, my_, mz_; ///< Grid max (Ang., Cartesian, orthogonal). - double nx_, ny_, nz_; ///< Number of bins in double precision (nonortho). + Vec3 OXYZ_; ///< Grid origin in Cartesian coordinates. + double dx_, dy_, dz_; ///< Grid spacing for binning (Ang., Cartesian). + double mx_, my_, mz_; ///< Grid max for binning (Ang., Cartesian, orthogonal). + double nx_, ny_, nz_; ///< Number of bins in double precision (for nonortho binning). double voxelvolume_; ///< Volume of a single voxel (Ang^3). Box box_; ///< Contain grid unit cell vectors, frac. vectors, volume. /// Internal pointer to the correct Calc routine From a394d3517fe9a2de609e889e3ae3f241e069f6fa Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 11:48:50 -0400 Subject: [PATCH 40/79] Add trans rot trans to Matrix_3x3 --- src/Matrix_3x3.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Matrix_3x3.h b/src/Matrix_3x3.h index 2302a8b5d7..4aced40ce4 100644 --- a/src/Matrix_3x3.h +++ b/src/Matrix_3x3.h @@ -92,6 +92,8 @@ class Matrix_3x3 { Matrix_3x3 operator*(Matrix_3x3 const&) const; /// Multiply this times transpose of 3x3 matrix Matrix_3x3 TransposeMult(Matrix_3x3 const&) const; + /// Calculate (Matrix * (point+T1)) + T2 + inline void Translate_Rotate_Translate(Vec3&, Vec3 const&, Vec3 const&) const; // TODO: Get rid of this const double* Dptr() const { return M_; } double* Dptr() { return M_; } @@ -119,4 +121,15 @@ Matrix_3x3 Matrix_3x3::Transposed() const { M_[1], M_[4], M_[7], M_[2], M_[5], M_[8] ); } + +/** Calculate (Matrix * (point+T1)) + T2 */ +void Matrix_3x3::Translate_Rotate_Translate(Vec3& point, Vec3 const& T1, Vec3 const& T2) const +{ + double x = point[0] + T1[0]; + double y = point[1] + T1[1]; + double z = point[2] + T1[2]; + point[0] = x*M_[0] + y*M_[1] + z*M_[2] + T2[0]; + point[1] = x*M_[3] + y*M_[4] + z*M_[5] + T2[1]; + point[2] = x*M_[6] + y*M_[7] + z*M_[8] + T2[2]; +} #endif From cfce4502933422a0522ce598addf22231d6c793e Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 12:00:28 -0400 Subject: [PATCH 41/79] Add function to set up box from 3 unit cell vectors --- src/Box.cpp | 20 ++++++++++++++++++++ src/Box.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/src/Box.cpp b/src/Box.cpp index 242acf342f..eb1b6bf20f 100644 --- a/src/Box.cpp +++ b/src/Box.cpp @@ -539,6 +539,26 @@ int Box::SetupFromUcell(const double* ucell) { return 0; } +/** Set up Xyz Abg array and frac cell from 3 vectors describing unit cell. */ +int Box::SetupFromUcell(Vec3 const& row1, Vec3 const& row2, Vec3 const& row3) { + std::copy(row1.Dptr(), row1.Dptr()+3, unitCell_.Dptr() ); + std::copy(row2.Dptr(), row2.Dptr()+3, unitCell_.Dptr()+3); + std::copy(row3.Dptr(), row3.Dptr()+3, unitCell_.Dptr()+6); + + CalcXyzAbgFromUcell(box_, unitCell_); + + cellVolume_ = CalcFracFromUcell(fracCell_, unitCell_); + +# ifdef DEBUG_BOX + printBoxStatus("SetupFromUcell(vecs)"); +# endif + if (CheckBox()) { + SetNoBox(); + return 1; + } + return 0; +} + /** Set unit cell and fractional cell from XYZ ABG parameters. */ int Box::SetupFromXyzAbg(double bx, double by, double bz, double ba, double bb, double bg) { box_[0] = bx; diff --git a/src/Box.h b/src/Box.h index 3edcf96083..5d0c649a57 100644 --- a/src/Box.h +++ b/src/Box.h @@ -44,6 +44,8 @@ class Box { int SetupFromUcell(Matrix_3x3 const& ucell) { return SetupFromUcell(ucell.Dptr()); } + int SetupFromUcell(Vec3 const&, Vec3 const&, Vec3 const&); + int SetupFromXyzAbg(double,double,double,double,double,double); int SetupFromXyzAbg(const double*); From a7c33390738d044e4cffb5a70b8f9bbcaa89b09e Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 12:02:24 -0400 Subject: [PATCH 42/79] First attempt to get function that can rotate the grid, not efficient yet --- src/GridBin.cpp | 14 ++++++++++++++ src/GridBin.h | 2 ++ src/Matrix_3x3.h | 14 +++++++++----- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/GridBin.cpp b/src/GridBin.cpp index 6d4043ce2c..d84bac410a 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -109,3 +109,17 @@ void GridBin::PrintDebug(const char* title) const mprintf("DEBUG: %s: sizes : %12.0f %12.0f %12.0f\n", title, nx_, ny_, nz_); mprintf("DEBUG: %s: voxel vol. : %12.4f\n", title, voxelvolume_); } + +/** Apply translation, rotation, translation to unit cell vectors and origin. */ +void GridBin::RotateGrid(Vec3 const& T1, Matrix_3x3 const& Rot, Vec3 const& T2) +{ + Vec3 newOxyz = Rot.Translate_Rotate_Translate(OXYZ_, T1, T2); + Vec3 newRow1 = Rot.Translate_Rotate_Translate(box_.UnitCell().Row1(), T1, T2); + Vec3 newRow2 = Rot.Translate_Rotate_Translate(box_.UnitCell().Row2(), T1, T2); + Vec3 newRow3 = Rot.Translate_Rotate_Translate(box_.UnitCell().Row3(), T2, T2); + // Set grid box and internal pointers based on box. TODO do not need full setup here... + box_.SetupFromUcell( newRow1, newRow2, newRow3 ); + SetupInternalPointers(); + //set_voxel_volume(); // Voxel volume should be unchanged + SetOrigin( newOxyz ); +} diff --git a/src/GridBin.h b/src/GridBin.h index 61c3378e04..530d7d7b0c 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -47,6 +47,8 @@ class GridBin { inline void SetOrigin(Vec3 const&); /// Set grid origin via given center point. inline void SetOriginFromCenter(Vec3 const&); + /// Apply translation, rotation, translation to unit cell vectors and origin. + void RotateGrid(Vec3 const&, Matrix_3x3 const&, Vec3 const&); /// Type for returning grid dimensions in terms of bins from setup routines typedef std::vector SizeArray; /// Set up for grid with given bins, origin, and box. diff --git a/src/Matrix_3x3.h b/src/Matrix_3x3.h index 4aced40ce4..9d34631475 100644 --- a/src/Matrix_3x3.h +++ b/src/Matrix_3x3.h @@ -93,7 +93,7 @@ class Matrix_3x3 { /// Multiply this times transpose of 3x3 matrix Matrix_3x3 TransposeMult(Matrix_3x3 const&) const; /// Calculate (Matrix * (point+T1)) + T2 - inline void Translate_Rotate_Translate(Vec3&, Vec3 const&, Vec3 const&) const; + inline Vec3 Translate_Rotate_Translate(Vec3 const&, Vec3 const&, Vec3 const&) const; // TODO: Get rid of this const double* Dptr() const { return M_; } double* Dptr() { return M_; } @@ -123,13 +123,17 @@ Matrix_3x3 Matrix_3x3::Transposed() const { } /** Calculate (Matrix * (point+T1)) + T2 */ -void Matrix_3x3::Translate_Rotate_Translate(Vec3& point, Vec3 const& T1, Vec3 const& T2) const +Vec3 Matrix_3x3::Translate_Rotate_Translate(Vec3 const& point, Vec3 const& T1, Vec3 const& T2) const { double x = point[0] + T1[0]; double y = point[1] + T1[1]; double z = point[2] + T1[2]; - point[0] = x*M_[0] + y*M_[1] + z*M_[2] + T2[0]; - point[1] = x*M_[3] + y*M_[4] + z*M_[5] + T2[1]; - point[2] = x*M_[6] + y*M_[7] + z*M_[8] + T2[2]; + //point[0] = x*M_[0] + y*M_[1] + z*M_[2] + T2[0]; + //point[1] = x*M_[3] + y*M_[4] + z*M_[5] + T2[1]; + //point[2] = x*M_[6] + y*M_[7] + z*M_[8] + T2[2]; + return Vec3( x*M_[0] + y*M_[1] + z*M_[2] + T2[0], + x*M_[3] + y*M_[4] + z*M_[5] + T2[1], + x*M_[6] + y*M_[7] + z*M_[8] + T2[2] ); + } #endif From db5572dacca77847971b38690d16a65a4531648c Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 13:07:20 -0400 Subject: [PATCH 43/79] Create MoveType --- src/GridAction.cpp | 18 +++++++++++------- src/GridAction.h | 8 +++++--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/GridAction.cpp b/src/GridAction.cpp index 18a57216b2..b4ba163a16 100644 --- a/src/GridAction.cpp +++ b/src/GridAction.cpp @@ -6,7 +6,7 @@ /** CONSTRUCTOR */ GridAction::GridAction() : gridOffsetType_(NO_OFFSET), - gridMoveType_(NO_OFFSET), + gridMoveType_(NO_MOVE), increment_(1.0) {} @@ -87,7 +87,7 @@ DataSet_GridFlt* GridAction::GridInit(const char* callingRoutine, ArgList& argIn CheckEven( nx, 'X' ); CheckEven( ny, 'Y' ); CheckEven( nz, 'Z' ); Vec3 gridctr(0.0, 0.0, 0.0); // Check if we want to specifically re-center the grid during DoAction - gridMoveType_ = NO_OFFSET; + gridMoveType_ = NO_MOVE; if (argIn.hasKey("gridcenter")) { double cx = argIn.getNextDouble(0.0); double cy = argIn.getNextDouble(0.0); @@ -96,12 +96,12 @@ DataSet_GridFlt* GridAction::GridInit(const char* callingRoutine, ArgList& argIn specifiedCenter = true; } else if (argIn.hasKey("boxcenter")) { specifiedCenter = true; - gridMoveType_ = BOX_CENTER; + gridMoveType_ = TO_BOX_CTR; } else { std::string maskCenterArg = argIn.GetStringKey("maskcenter"); if (!maskCenterArg.empty()) { specifiedCenter = true; - gridMoveType_ = MASK_CENTER; + gridMoveType_ = TO_MASK_CTR; if (centerMask_.SetMaskString( maskCenterArg )) return 0; } } @@ -155,14 +155,18 @@ int GridAction::ParallelGridInit(Parallel::Comm const& commIn, DataSet_GridFlt* // GridAction::GridInfo() void GridAction::GridInfo(DataSet_GridFlt const& grid) { - if (gridOffsetType_ == BOX_CENTER) + if (gridOffsetType_ == NO_OFFSET) + mprintf("\tNo offset will be applied to points.\n"); + else if (gridOffsetType_ == BOX_CENTER) mprintf("\tOffset for points is box center.\n"); else if (gridOffsetType_ == MASK_CENTER) mprintf("\tOffset for points is center of atoms in mask [%s]\n", centerMask_.MaskString()); - if (gridMoveType_ == BOX_CENTER) + if (gridMoveType_ == NO_MOVE) + mprintf("\tGrid will not move.\n"); + else if (gridMoveType_ == TO_BOX_CTR) mprintf("\tGrid will be kept centered at the box center.\n"); - else if (gridMoveType_ == MASK_CENTER) + else if (gridMoveType_ == TO_MASK_CTR) mprintf("\tGrid will be kept centered on atoms in mask [%s]\n", centerMask_.MaskString()); if (increment_ > 0) diff --git a/src/GridAction.h b/src/GridAction.h index eb8ad8d0b3..f7efcd8204 100644 --- a/src/GridAction.h +++ b/src/GridAction.h @@ -13,6 +13,8 @@ class GridAction { public: /// Indicate whether to apply an offset to coords before gridding. enum OffsetType { NO_OFFSET = 0, BOX_CENTER, MASK_CENTER }; + /// Indicate where grid should be located + enum MoveType { NO_MOVE = 0, TO_BOX_CTR, TO_MASK_CTR, RMS_FIT }; /// CONSTRUCTOR GridAction(); /// \return List of keywords recognized by GridInit. @@ -39,7 +41,7 @@ class GridAction { float Increment() const { return increment_; } private: OffsetType gridOffsetType_; - OffsetType gridMoveType_; + MoveType gridMoveType_; AtomMask centerMask_; float increment_; ///< Set to -1 if negative, 1 if not. }; @@ -64,9 +66,9 @@ void GridAction::GridFrame(Frame const& currentFrame, AtomMask const& mask, /** Move grid if necessary. */ void GridAction::MoveGrid(Frame const& currentFrame, DataSet_GridFlt& grid) { - if (gridMoveType_ == BOX_CENTER) + if (gridMoveType_ == TO_BOX_CTR) grid.SetGridCenter( currentFrame.BoxCrd().Center() ); - else if (gridMoveType_ == MASK_CENTER) + else if (gridMoveType_ == TO_MASK_CTR) grid.SetGridCenter( currentFrame.VGeometricCenter( centerMask_ ) ); } #endif From 192850ce8a4c8da0ca22ab9c181368d0bd97a5a8 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 13:50:12 -0400 Subject: [PATCH 44/79] Fix typo --- src/GridBin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GridBin.cpp b/src/GridBin.cpp index d84bac410a..69aa36e820 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -116,7 +116,7 @@ void GridBin::RotateGrid(Vec3 const& T1, Matrix_3x3 const& Rot, Vec3 const& T2) Vec3 newOxyz = Rot.Translate_Rotate_Translate(OXYZ_, T1, T2); Vec3 newRow1 = Rot.Translate_Rotate_Translate(box_.UnitCell().Row1(), T1, T2); Vec3 newRow2 = Rot.Translate_Rotate_Translate(box_.UnitCell().Row2(), T1, T2); - Vec3 newRow3 = Rot.Translate_Rotate_Translate(box_.UnitCell().Row3(), T2, T2); + Vec3 newRow3 = Rot.Translate_Rotate_Translate(box_.UnitCell().Row3(), T1, T2); // Set grid box and internal pointers based on box. TODO do not need full setup here... box_.SetupFromUcell( newRow1, newRow2, newRow3 ); SetupInternalPointers(); From af3a4363547538218f31d6080fda455be5207311 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 13:50:37 -0400 Subject: [PATCH 45/79] Allow DataSet_3D grid to be rotated --- src/DataSet_3D.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DataSet_3D.h b/src/DataSet_3D.h index 4638af99d3..c56a6edaf7 100644 --- a/src/DataSet_3D.h +++ b/src/DataSet_3D.h @@ -65,6 +65,8 @@ class DataSet_3D : public DataSet { int Allocate_N_O_Box(size_t,size_t,size_t, Vec3 const&, Box const&); /// Move grid center void SetGridCenter(Vec3 const& cxyz) { gridBin_.SetOriginFromCenter( cxyz); } + /// Rotate grid + void RotateGrid(Vec3 const& T1, Matrix_3x3 const& Rot, Vec3 const& T2) { gridBin_.RotateGrid(T1, Rot, T2); } /// Print grid info. void GridInfo() const; // ------------------------------------------- From 9a53b6463e3f0e96a280a33535788632b3a6f7eb Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 29 Jun 2021 13:51:14 -0400 Subject: [PATCH 46/79] Implement the rmsfit keyword for grids --- src/GridAction.cpp | 22 +++++++++++++++++++--- src/GridAction.h | 17 +++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/GridAction.cpp b/src/GridAction.cpp index b4ba163a16..5ff7159a6d 100644 --- a/src/GridAction.cpp +++ b/src/GridAction.cpp @@ -7,7 +7,8 @@ GridAction::GridAction() : gridOffsetType_(NO_OFFSET), gridMoveType_(NO_MOVE), - increment_(1.0) + increment_(1.0), + firstFrame_(false) {} // GridAction::HelpText @@ -16,7 +17,8 @@ const char* GridAction::HelpText = "\t \n" "\t [ { gridcenter |\n" "\t boxcenter |\n" - "\t maskcenter } ]\n" + "\t maskcenter |\n" + "\t rmsfit } ]\n" "\t[box|origin|center ] [negative] [name ]"; static inline void CheckEven(int& N, char dir) { @@ -99,10 +101,15 @@ DataSet_GridFlt* GridAction::GridInit(const char* callingRoutine, ArgList& argIn gridMoveType_ = TO_BOX_CTR; } else { std::string maskCenterArg = argIn.GetStringKey("maskcenter"); + std::string rmsFitArg = argIn.GetStringKey("rmsfit"); if (!maskCenterArg.empty()) { specifiedCenter = true; gridMoveType_ = TO_MASK_CTR; if (centerMask_.SetMaskString( maskCenterArg )) return 0; + } else if (!rmsFitArg.empty()) { + specifiedCenter = true; + gridMoveType_ = RMS_FIT; + if (centerMask_.SetMaskString( rmsFitArg )) return 0; } } Grid = (DataSet_GridFlt*)DSL.AddSet( DataSet::GRID_FLT, argIn.GetStringKey("name"), "GRID" ); @@ -169,6 +176,9 @@ void GridAction::GridInfo(DataSet_GridFlt const& grid) { else if (gridMoveType_ == TO_MASK_CTR) mprintf("\tGrid will be kept centered on atoms in mask [%s]\n", centerMask_.MaskString()); + else if (gridMoveType_ == RMS_FIT) + mprintf("\tGrid will be RMS-fit using atoms in mask [%s]\n", + centerMask_.MaskString()); if (increment_ > 0) mprintf("\tCalculating positive density.\n"); else @@ -192,9 +202,15 @@ int GridAction::GridSetup(Topology const& currentParm, CoordinateInfo const& cIn if ( currentParm.SetupIntegerMask( centerMask_ ) ) return 1; centerMask_.MaskInfo(); if ( centerMask_.None() ) { - mprinterr("Error: No atoms selected for grid center mask [%s]\n", centerMask_.MaskString()); + mprinterr("Error: No atoms selected for grid mask [%s]\n", centerMask_.MaskString()); return 1; } } + // Set up frames if needed + if (gridMoveType_ == RMS_FIT) { + tgt_.SetupFrameFromMask(centerMask_, currentParm.Atoms()); + ref_ = tgt_; + firstFrame_ = true; + } return 0; } diff --git a/src/GridAction.h b/src/GridAction.h index f7efcd8204..4e9efd64c7 100644 --- a/src/GridAction.h +++ b/src/GridAction.h @@ -44,6 +44,9 @@ class GridAction { MoveType gridMoveType_; AtomMask centerMask_; float increment_; ///< Set to -1 if negative, 1 if not. + Frame tgt_; ///< For MoveType RMS_FIT, previous frames selected coordinates + Frame ref_; ///< For MoveType RMS_FIT, current frames selected coordinates + bool firstFrame_; ///< For MoveType RMS_FIT, true if this is the first frame (no fit needed) }; // ----- INLINE FUNCTIONS ------------------------------------------------------ void GridAction::GridFrame(Frame const& currentFrame, AtomMask const& mask, @@ -70,5 +73,19 @@ void GridAction::MoveGrid(Frame const& currentFrame, DataSet_GridFlt& grid) grid.SetGridCenter( currentFrame.BoxCrd().Center() ); else if (gridMoveType_ == TO_MASK_CTR) grid.SetGridCenter( currentFrame.VGeometricCenter( centerMask_ ) ); + else if (gridMoveType_ == RMS_FIT) { + grid.SetGridCenter( currentFrame.VGeometricCenter( centerMask_ ) ); + if (firstFrame_) { + tgt_.SetFrame( currentFrame, centerMask_ ); + firstFrame_ = false; + } else { + ref_.SetFrame( currentFrame, centerMask_ ); + Matrix_3x3 Rot; + Vec3 T1, T2; + tgt_.RMSD( ref_, Rot, T1, T2, false ); + grid.RotateGrid( T1, Rot, T2 ); + tgt_.SetFrame( currentFrame, centerMask_ ); + } + } } #endif From 126b7a39ce43cb54b33a5adb3956ac83e4b84e3e Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 30 Jun 2021 13:54:10 -0400 Subject: [PATCH 47/79] Only rotate the unit cell and set up pointers --- src/GridBin.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/GridBin.cpp b/src/GridBin.cpp index 69aa36e820..1029af37a3 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -113,13 +113,15 @@ void GridBin::PrintDebug(const char* title) const /** Apply translation, rotation, translation to unit cell vectors and origin. */ void GridBin::RotateGrid(Vec3 const& T1, Matrix_3x3 const& Rot, Vec3 const& T2) { + box_.RotateUcell(Rot); +/* Vec3 newOxyz = Rot.Translate_Rotate_Translate(OXYZ_, T1, T2); Vec3 newRow1 = Rot.Translate_Rotate_Translate(box_.UnitCell().Row1(), T1, T2); Vec3 newRow2 = Rot.Translate_Rotate_Translate(box_.UnitCell().Row2(), T1, T2); Vec3 newRow3 = Rot.Translate_Rotate_Translate(box_.UnitCell().Row3(), T1, T2); // Set grid box and internal pointers based on box. TODO do not need full setup here... - box_.SetupFromUcell( newRow1, newRow2, newRow3 ); + box_.SetupFromUcell( newRow1, newRow2, newRow3 );*/ SetupInternalPointers(); //set_voxel_volume(); // Voxel volume should be unchanged - SetOrigin( newOxyz ); +/* SetOrigin( newOxyz );*/ } From 06b58117237acdbb7c9b77538f50dfc49d3a8c65 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 30 Jun 2021 18:23:28 -0400 Subject: [PATCH 48/79] Walk back some unused changes --- src/Box.cpp | 20 -------------------- src/Box.h | 2 -- src/Matrix_3x3.h | 17 ----------------- 3 files changed, 39 deletions(-) diff --git a/src/Box.cpp b/src/Box.cpp index eb1b6bf20f..242acf342f 100644 --- a/src/Box.cpp +++ b/src/Box.cpp @@ -539,26 +539,6 @@ int Box::SetupFromUcell(const double* ucell) { return 0; } -/** Set up Xyz Abg array and frac cell from 3 vectors describing unit cell. */ -int Box::SetupFromUcell(Vec3 const& row1, Vec3 const& row2, Vec3 const& row3) { - std::copy(row1.Dptr(), row1.Dptr()+3, unitCell_.Dptr() ); - std::copy(row2.Dptr(), row2.Dptr()+3, unitCell_.Dptr()+3); - std::copy(row3.Dptr(), row3.Dptr()+3, unitCell_.Dptr()+6); - - CalcXyzAbgFromUcell(box_, unitCell_); - - cellVolume_ = CalcFracFromUcell(fracCell_, unitCell_); - -# ifdef DEBUG_BOX - printBoxStatus("SetupFromUcell(vecs)"); -# endif - if (CheckBox()) { - SetNoBox(); - return 1; - } - return 0; -} - /** Set unit cell and fractional cell from XYZ ABG parameters. */ int Box::SetupFromXyzAbg(double bx, double by, double bz, double ba, double bb, double bg) { box_[0] = bx; diff --git a/src/Box.h b/src/Box.h index 5d0c649a57..3edcf96083 100644 --- a/src/Box.h +++ b/src/Box.h @@ -44,8 +44,6 @@ class Box { int SetupFromUcell(Matrix_3x3 const& ucell) { return SetupFromUcell(ucell.Dptr()); } - int SetupFromUcell(Vec3 const&, Vec3 const&, Vec3 const&); - int SetupFromXyzAbg(double,double,double,double,double,double); int SetupFromXyzAbg(const double*); diff --git a/src/Matrix_3x3.h b/src/Matrix_3x3.h index 9d34631475..2302a8b5d7 100644 --- a/src/Matrix_3x3.h +++ b/src/Matrix_3x3.h @@ -92,8 +92,6 @@ class Matrix_3x3 { Matrix_3x3 operator*(Matrix_3x3 const&) const; /// Multiply this times transpose of 3x3 matrix Matrix_3x3 TransposeMult(Matrix_3x3 const&) const; - /// Calculate (Matrix * (point+T1)) + T2 - inline Vec3 Translate_Rotate_Translate(Vec3 const&, Vec3 const&, Vec3 const&) const; // TODO: Get rid of this const double* Dptr() const { return M_; } double* Dptr() { return M_; } @@ -121,19 +119,4 @@ Matrix_3x3 Matrix_3x3::Transposed() const { M_[1], M_[4], M_[7], M_[2], M_[5], M_[8] ); } - -/** Calculate (Matrix * (point+T1)) + T2 */ -Vec3 Matrix_3x3::Translate_Rotate_Translate(Vec3 const& point, Vec3 const& T1, Vec3 const& T2) const -{ - double x = point[0] + T1[0]; - double y = point[1] + T1[1]; - double z = point[2] + T1[2]; - //point[0] = x*M_[0] + y*M_[1] + z*M_[2] + T2[0]; - //point[1] = x*M_[3] + y*M_[4] + z*M_[5] + T2[1]; - //point[2] = x*M_[6] + y*M_[7] + z*M_[8] + T2[2]; - return Vec3( x*M_[0] + y*M_[1] + z*M_[2] + T2[0], - x*M_[3] + y*M_[4] + z*M_[5] + T2[1], - x*M_[6] + y*M_[7] + z*M_[8] + T2[2] ); - -} #endif From 41e98abd4395361367dabfad0b9aa7c5c1e2b079 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 30 Jun 2021 18:41:29 -0400 Subject: [PATCH 49/79] Trim up the grid rotation function call --- src/DataSet_3D.h | 4 ++-- src/GridAction.h | 2 +- src/GridBin.cpp | 13 +++---------- src/GridBin.h | 4 ++-- 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/DataSet_3D.h b/src/DataSet_3D.h index c56a6edaf7..7c3598870a 100644 --- a/src/DataSet_3D.h +++ b/src/DataSet_3D.h @@ -65,8 +65,8 @@ class DataSet_3D : public DataSet { int Allocate_N_O_Box(size_t,size_t,size_t, Vec3 const&, Box const&); /// Move grid center void SetGridCenter(Vec3 const& cxyz) { gridBin_.SetOriginFromCenter( cxyz); } - /// Rotate grid - void RotateGrid(Vec3 const& T1, Matrix_3x3 const& Rot, Vec3 const& T2) { gridBin_.RotateGrid(T1, Rot, T2); } + /// Rotate the grid using the given rotation matrix. + void Rotate_3D_Grid(Matrix_3x3 const& Rot) { gridBin_.RotateGrid(Rot); } /// Print grid info. void GridInfo() const; // ------------------------------------------- diff --git a/src/GridAction.h b/src/GridAction.h index 4e9efd64c7..a2480fca06 100644 --- a/src/GridAction.h +++ b/src/GridAction.h @@ -83,7 +83,7 @@ void GridAction::MoveGrid(Frame const& currentFrame, DataSet_GridFlt& grid) Matrix_3x3 Rot; Vec3 T1, T2; tgt_.RMSD( ref_, Rot, T1, T2, false ); - grid.RotateGrid( T1, Rot, T2 ); + grid.Rotate_3D_Grid( Rot ); tgt_.SetFrame( currentFrame, centerMask_ ); } } diff --git a/src/GridBin.cpp b/src/GridBin.cpp index 1029af37a3..a3420f2c09 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -110,18 +110,11 @@ void GridBin::PrintDebug(const char* title) const mprintf("DEBUG: %s: voxel vol. : %12.4f\n", title, voxelvolume_); } -/** Apply translation, rotation, translation to unit cell vectors and origin. */ -void GridBin::RotateGrid(Vec3 const& T1, Matrix_3x3 const& Rot, Vec3 const& T2) +/** Apply rotation to grid unit cell vectors. */ +void GridBin::RotateGrid(Matrix_3x3 const& Rot) { box_.RotateUcell(Rot); -/* - Vec3 newOxyz = Rot.Translate_Rotate_Translate(OXYZ_, T1, T2); - Vec3 newRow1 = Rot.Translate_Rotate_Translate(box_.UnitCell().Row1(), T1, T2); - Vec3 newRow2 = Rot.Translate_Rotate_Translate(box_.UnitCell().Row2(), T1, T2); - Vec3 newRow3 = Rot.Translate_Rotate_Translate(box_.UnitCell().Row3(), T1, T2); - // Set grid box and internal pointers based on box. TODO do not need full setup here... - box_.SetupFromUcell( newRow1, newRow2, newRow3 );*/ + SetupInternalPointers(); //set_voxel_volume(); // Voxel volume should be unchanged -/* SetOrigin( newOxyz );*/ } diff --git a/src/GridBin.h b/src/GridBin.h index 530d7d7b0c..1f843a22f6 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -47,8 +47,8 @@ class GridBin { inline void SetOrigin(Vec3 const&); /// Set grid origin via given center point. inline void SetOriginFromCenter(Vec3 const&); - /// Apply translation, rotation, translation to unit cell vectors and origin. - void RotateGrid(Vec3 const&, Matrix_3x3 const&, Vec3 const&); + /// Apply rotation matrix to grid unit cell vectors. + void RotateGrid(Matrix_3x3 const&); /// Type for returning grid dimensions in terms of bins from setup routines typedef std::vector SizeArray; /// Set up for grid with given bins, origin, and box. From 26edcfda4438c8581a5269f76b1e1f9689ef5888 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 2 Jul 2021 08:40:01 -0400 Subject: [PATCH 50/79] Properly handle rotation of origin coord --- src/GridBin.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/GridBin.cpp b/src/GridBin.cpp index a3420f2c09..ad12921441 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -110,11 +110,46 @@ void GridBin::PrintDebug(const char* title) const mprintf("DEBUG: %s: voxel vol. : %12.4f\n", title, voxelvolume_); } +/// Apply translation, rotation, translation +static inline void T_R_T(double* point, Vec3 const& t1, Matrix_3x3 const& R, Vec3 const& t2) +{ + double x = point[0] + t1[0]; + double y = point[1] + t1[1]; + double z = point[2] + t1[2]; + point[0] = x*R[0] + y*R[1] + z*R[2] + t2[0]; + point[1] = x*R[3] + y*R[4] + z*R[5] + t2[1]; + point[2] = x*R[6] + y*R[7] + z*R[8] + t2[2]; +} + /** Apply rotation to grid unit cell vectors. */ void GridBin::RotateGrid(Matrix_3x3 const& Rot) { + Vec3 gridCtrXyz = GridCenter(); + mprintf("DEBUG: Original oxyz= %f %f %f\n", OXYZ_[0], OXYZ_[1], OXYZ_[2]); box_.RotateUcell(Rot); +/* + // Get grid unit cell center vector. + Vec3 centerVec = box_.UnitCell().TransposeMult( Vec3(0.5, 0.5, 0.5) ); + Vec3 minus_centerVec( -centerVec[0], -centerVec[1], -centerVec[2] ); + Vec3 gridCtrXyz = OXYZ_ + centerVec; + + // DEBUG + centerVec.Zero(); + minus_centerVec.Zero(); + + // Rotate those unit cell vectors + Matrix_3x3 new_ucell = box_.UnitCell(); + T_R_T( new_ucell.Dptr(), minus_centerVec, Rot, centerVec ); + T_R_T( new_ucell.Dptr()+3, minus_centerVec, Rot, centerVec ); + T_R_T( new_ucell.Dptr()+6, minus_centerVec, Rot, centerVec ); + + // Set up the box from rotated cell + box_.SetupFromUcell( new_ucell );*/ SetupInternalPointers(); //set_voxel_volume(); // Voxel volume should be unchanged + + // Set the grid back at the original center + SetOriginFromCenter( gridCtrXyz ); + mprintf("DEBUG: New oxyz= %f %f %f\n", OXYZ_[0], OXYZ_[1], OXYZ_[2]); } From d97133fd43adbf18f0bd2787e0e61b04deb98856 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 2 Jul 2021 09:45:11 -0400 Subject: [PATCH 51/79] Remove bad code --- src/GridBin.cpp | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/src/GridBin.cpp b/src/GridBin.cpp index ad12921441..c03610484d 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -124,32 +124,16 @@ static inline void T_R_T(double* point, Vec3 const& t1, Matrix_3x3 const& R, Vec /** Apply rotation to grid unit cell vectors. */ void GridBin::RotateGrid(Matrix_3x3 const& Rot) { + // Save the grid center coords TODO should this just always be saved? Vec3 gridCtrXyz = GridCenter(); - mprintf("DEBUG: Original oxyz= %f %f %f\n", OXYZ_[0], OXYZ_[1], OXYZ_[2]); + //mprintf("DEBUG: Original oxyz= %f %f %f\n", OXYZ_[0], OXYZ_[1], OXYZ_[2]); + // Rotate grid unit cell box_.RotateUcell(Rot); - -/* - // Get grid unit cell center vector. - Vec3 centerVec = box_.UnitCell().TransposeMult( Vec3(0.5, 0.5, 0.5) ); - Vec3 minus_centerVec( -centerVec[0], -centerVec[1], -centerVec[2] ); - Vec3 gridCtrXyz = OXYZ_ + centerVec; - - // DEBUG - centerVec.Zero(); - minus_centerVec.Zero(); - - // Rotate those unit cell vectors - Matrix_3x3 new_ucell = box_.UnitCell(); - T_R_T( new_ucell.Dptr(), minus_centerVec, Rot, centerVec ); - T_R_T( new_ucell.Dptr()+3, minus_centerVec, Rot, centerVec ); - T_R_T( new_ucell.Dptr()+6, minus_centerVec, Rot, centerVec ); - - // Set up the box from rotated cell - box_.SetupFromUcell( new_ucell );*/ + // Update internal pointers based on new cell orientation SetupInternalPointers(); //set_voxel_volume(); // Voxel volume should be unchanged - - // Set the grid back at the original center + // Update origin by setting the grid back at the original center + // with the new grid unit cell. SetOriginFromCenter( gridCtrXyz ); - mprintf("DEBUG: New oxyz= %f %f %f\n", OXYZ_[0], OXYZ_[1], OXYZ_[2]); + //mprintf("DEBUG: New oxyz= %f %f %f\n", OXYZ_[0], OXYZ_[1], OXYZ_[2]); } From eebd3a8c2900037e4d47987056cc046c30078728 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 2 Jul 2021 09:45:51 -0400 Subject: [PATCH 52/79] Comment out unused code --- src/GridBin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/GridBin.cpp b/src/GridBin.cpp index c03610484d..7a7dcf5fe6 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -111,6 +111,7 @@ void GridBin::PrintDebug(const char* title) const } /// Apply translation, rotation, translation +/* static inline void T_R_T(double* point, Vec3 const& t1, Matrix_3x3 const& R, Vec3 const& t2) { double x = point[0] + t1[0]; @@ -120,6 +121,7 @@ static inline void T_R_T(double* point, Vec3 const& t1, Matrix_3x3 const& R, Vec point[1] = x*R[3] + y*R[4] + z*R[5] + t2[1]; point[2] = x*R[6] + y*R[7] + z*R[8] + t2[2]; } +*/ /** Apply rotation to grid unit cell vectors. */ void GridBin::RotateGrid(Matrix_3x3 const& Rot) From e806acdb006ba46b85f9f241f947086a71a1bb69 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 2 Jul 2021 09:59:23 -0400 Subject: [PATCH 53/79] Function to X-align the grid --- src/GridBin.cpp | 20 ++++++++++++++++++++ src/GridBin.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/src/GridBin.cpp b/src/GridBin.cpp index 7a7dcf5fe6..ca2f7a2dc5 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -139,3 +139,23 @@ void GridBin::RotateGrid(Matrix_3x3 const& Rot) SetOriginFromCenter( gridCtrXyz ); //mprintf("DEBUG: New oxyz= %f %f %f\n", OXYZ_[0], OXYZ_[1], OXYZ_[2]); } + +/** X-align the current grid. */ +void GridBin::X_align_grid() { + // Save the grid center coords + Vec3 gridCtrXyz = GridCenter(); + // Create X-aligned box based on current xyz abg. + double newbox[6]; + newbox[Box::X] = box_.Param(Box::X); + newbox[Box::Y] = box_.Param(Box::Y); + newbox[Box::Z] = box_.Param(Box::Z); + newbox[Box::ALPHA] = box_.Param(Box::ALPHA); + newbox[Box::BETA] = box_.Param(Box::BETA); + newbox[Box::GAMMA] = box_.Param(Box::GAMMA); + box_.AssignFromXyzAbg( newbox ); + // Update internal pointers based on new cell orientation + SetupInternalPointers(); + // Update origin by setting the grid back at the original center + // with the new grid unit cell. + SetOriginFromCenter( gridCtrXyz ); +} diff --git a/src/GridBin.h b/src/GridBin.h index 1f843a22f6..913375d6e9 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -49,6 +49,8 @@ class GridBin { inline void SetOriginFromCenter(Vec3 const&); /// Apply rotation matrix to grid unit cell vectors. void RotateGrid(Matrix_3x3 const&); + /// Make the grid X-aligned + void X_align_grid(); /// Type for returning grid dimensions in terms of bins from setup routines typedef std::vector SizeArray; /// Set up for grid with given bins, origin, and box. From f7a185f1b1349041b81efce7df38857c1b6c169d Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 2 Jul 2021 10:06:13 -0400 Subject: [PATCH 54/79] Create Xalign_3D_Grid function --- src/DataSet_3D.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DataSet_3D.h b/src/DataSet_3D.h index 7c3598870a..fcfc435578 100644 --- a/src/DataSet_3D.h +++ b/src/DataSet_3D.h @@ -67,6 +67,8 @@ class DataSet_3D : public DataSet { void SetGridCenter(Vec3 const& cxyz) { gridBin_.SetOriginFromCenter( cxyz); } /// Rotate the grid using the given rotation matrix. void Rotate_3D_Grid(Matrix_3x3 const& Rot) { gridBin_.RotateGrid(Rot); } + /// X-align the grid + void Xalign_3D_Grid() { gridBin_.X_align_grid(); } /// Print grid info. void GridInfo() const; // ------------------------------------------- From b4550b84a7be4176435c2ed4f8301780dbb47406 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 2 Jul 2021 10:09:58 -0400 Subject: [PATCH 55/79] Add function to ensure grid is x-aligned at the end of processing --- src/Action_Grid.cpp | 1 + src/GridAction.cpp | 9 ++++++++- src/GridAction.h | 8 ++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Action_Grid.cpp b/src/Action_Grid.cpp index 253a289766..487555caee 100644 --- a/src/Action_Grid.cpp +++ b/src/Action_Grid.cpp @@ -149,6 +149,7 @@ Action::RetType Action_Grid::DoAction(int frameNum, ActionFrame& frm) { // Action_Grid::print() void Action_Grid::Print() { if (nframes_ < 1) return; + FinishGrid( *grid_ ); // Perform normalization and find max. double gridMax = 0.0; if (normalize_ == NONE) { diff --git a/src/GridAction.cpp b/src/GridAction.cpp index 5ff7159a6d..6943a01297 100644 --- a/src/GridAction.cpp +++ b/src/GridAction.cpp @@ -8,7 +8,8 @@ GridAction::GridAction() : gridOffsetType_(NO_OFFSET), gridMoveType_(NO_MOVE), increment_(1.0), - firstFrame_(false) + firstFrame_(false), + x_align_(true) {} // GridAction::HelpText @@ -214,3 +215,9 @@ int GridAction::GridSetup(Topology const& currentParm, CoordinateInfo const& cIn } return 0; } + +/** Any final actions to grid. */ +void GridAction::FinishGrid(DataSet_GridFlt& grid) const { + if (x_align_) + grid.Xalign_3D_Grid(); +} diff --git a/src/GridAction.h b/src/GridAction.h index a2480fca06..f58db617f3 100644 --- a/src/GridAction.h +++ b/src/GridAction.h @@ -30,9 +30,11 @@ class GridAction { /// Perform any setup necessary for given Topology/CoordinateInfo int GridSetup(Topology const&, CoordinateInfo const&); /// Place atoms selected by given mask in given Frame on the given grid. - inline void GridFrame(Frame const&, AtomMask const&, DataSet_GridFlt&); + inline void GridFrame(Frame const&, AtomMask const&, DataSet_GridFlt&) const; /// Move grid if necessary inline void MoveGrid(Frame const&, DataSet_GridFlt&); + /// Anything needed to finalize the grid + void FinishGrid(DataSet_GridFlt&) const; /// \return Type of offset to apply to coords before gridding. OffsetType GridOffsetType() const { return gridOffsetType_; } /// \return Mask to use for centering grid @@ -47,10 +49,12 @@ class GridAction { Frame tgt_; ///< For MoveType RMS_FIT, previous frames selected coordinates Frame ref_; ///< For MoveType RMS_FIT, current frames selected coordinates bool firstFrame_; ///< For MoveType RMS_FIT, true if this is the first frame (no fit needed) + bool x_align_; ///< For MoveType RMS_FIT, if true ensure grid is X-aligned in FinishGrid(); }; // ----- INLINE FUNCTIONS ------------------------------------------------------ void GridAction::GridFrame(Frame const& currentFrame, AtomMask const& mask, - DataSet_GridFlt& grid) + DataSet_GridFlt& grid) +const { if (gridOffsetType_ == BOX_CENTER) { Vec3 offset = currentFrame.BoxCrd().Center(); From 772d12b4e02cccd604d158ec82b216b809c550e2 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 2 Jul 2021 10:12:27 -0400 Subject: [PATCH 56/79] Add FinishGrid to all grid actions --- src/Action_Dipole.cpp | 2 ++ src/Action_Grid.cpp | 2 +- src/Action_GridFreeEnergy.cpp | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Action_Dipole.cpp b/src/Action_Dipole.cpp index a83f06fbd0..126d9fe8cd 100644 --- a/src/Action_Dipole.cpp +++ b/src/Action_Dipole.cpp @@ -190,6 +190,8 @@ int Action_Dipole::SyncAction() { * comes with Midas/Plus. */ void Action_Dipole::Print() { + if (grid_ == 0) return + FinishGrid( *grid_ ); double max_density; // Write header diff --git a/src/Action_Grid.cpp b/src/Action_Grid.cpp index 487555caee..2271419fa4 100644 --- a/src/Action_Grid.cpp +++ b/src/Action_Grid.cpp @@ -148,7 +148,7 @@ Action::RetType Action_Grid::DoAction(int frameNum, ActionFrame& frm) { // Action_Grid::print() void Action_Grid::Print() { - if (nframes_ < 1) return; + if (nframes_ < 1 || grid_ == 0) return; FinishGrid( *grid_ ); // Perform normalization and find max. double gridMax = 0.0; diff --git a/src/Action_GridFreeEnergy.cpp b/src/Action_GridFreeEnergy.cpp index b5d4a6e15c..cc8794894a 100644 --- a/src/Action_GridFreeEnergy.cpp +++ b/src/Action_GridFreeEnergy.cpp @@ -90,6 +90,8 @@ Action::RetType Action_GridFreeEnergy::DoAction(int frameNum, ActionFrame& frm) // Action_GridFreeEnergy::print() void Action_GridFreeEnergy::Print() { + if (grid_ == 0) return; + FinishGrid( *grid_ ); /* How times does this occupancy count value arise? * i.e. if * voxelOccupancyCount[50] = 10 From 6eb20adddce40b8eab72682a237c16a5535e2ed1 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 2 Jul 2021 10:54:18 -0400 Subject: [PATCH 57/79] Print informative message if grid is being X-aligned --- src/GridAction.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/GridAction.cpp b/src/GridAction.cpp index 6943a01297..ce4247cf04 100644 --- a/src/GridAction.cpp +++ b/src/GridAction.cpp @@ -218,6 +218,10 @@ int GridAction::GridSetup(Topology const& currentParm, CoordinateInfo const& cIn /** Any final actions to grid. */ void GridAction::FinishGrid(DataSet_GridFlt& grid) const { - if (x_align_) - grid.Xalign_3D_Grid(); + if (x_align_) { + if (!grid.Bin().IsOrthoGrid()) { + mprintf("\tEnsuring grid '%s' is X-aligned.\n", grid.legend()); + grid.Xalign_3D_Grid(); + } + } } From 9253202bcacf8860c83dd7ce146feaacbe82229a Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 2 Jul 2021 10:59:13 -0400 Subject: [PATCH 58/79] Fix x-align check --- src/GridAction.cpp | 2 +- src/GridBin.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/GridAction.cpp b/src/GridAction.cpp index ce4247cf04..c44b5755ac 100644 --- a/src/GridAction.cpp +++ b/src/GridAction.cpp @@ -219,7 +219,7 @@ int GridAction::GridSetup(Topology const& currentParm, CoordinateInfo const& cIn /** Any final actions to grid. */ void GridAction::FinishGrid(DataSet_GridFlt& grid) const { if (x_align_) { - if (!grid.Bin().IsOrthoGrid()) { + if (!grid.Bin().IsXalignedGrid()) { mprintf("\tEnsuring grid '%s' is X-aligned.\n", grid.legend()); grid.Xalign_3D_Grid(); } diff --git a/src/GridBin.h b/src/GridBin.h index 913375d6e9..5050ffe70a 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -25,6 +25,8 @@ class GridBin { inline Box const& GridBox() const { return box_; } /// \return true if Grid is X-aligned and orthogonal. TODO this may not be necessary inline bool IsOrthoGrid() const { return box_.Is_X_Aligned_Ortho(); } + /// \return true if Grid is X-aligned + inline bool IsXalignedGrid() const { return box_.Is_X_Aligned(); } /// \return Voxel volume. inline double VoxelVolume() const { return voxelvolume_; } /// \return a copy of this GridBin. From d0a728cfba91726354a98b23ab0e1828593d08f4 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 6 Jul 2021 11:34:44 -0400 Subject: [PATCH 59/79] Store number of frames in separate variable in case we are catting to ourselves. --- src/Exec_CatCrd.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Exec_CatCrd.cpp b/src/Exec_CatCrd.cpp index b240752e43..c73d6766bd 100644 --- a/src/Exec_CatCrd.cpp +++ b/src/Exec_CatCrd.cpp @@ -83,7 +83,8 @@ Exec::RetType Exec_CatCrd::Execute(CpptrajState& State, ArgList& argIn) { mprintf("\t'%s'\n", (*in)->legend()); Frame frameIn = (*in)->AllocateFrame(); - for (unsigned int frm = 0; frm != (*in)->Size(); frm++) { + unsigned int nFrames = (*in)->Size(); + for (unsigned int frm = 0; frm != nFrames; frm++) { (*in)->GetFrame(frm, frameIn); coordsOut->AddFrame( frameIn ); } From 3e15e8cc39e79ff792644238dfb5391fc67745c0 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 24 Aug 2021 11:13:03 -0400 Subject: [PATCH 60/79] Instead of rotating the grid from previous to current frame, rotate from first frame to current frame. Since rms fit to a single reference is usually what is done before grid, this gives results more in line to what is expected. --- src/DataSet_3D.h | 2 ++ src/GridAction.h | 14 +++++++++++--- src/GridBin.cpp | 13 +++++++++++++ src/GridBin.h | 2 ++ 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/DataSet_3D.h b/src/DataSet_3D.h index fcfc435578..dd51af63fa 100644 --- a/src/DataSet_3D.h +++ b/src/DataSet_3D.h @@ -65,6 +65,8 @@ class DataSet_3D : public DataSet { int Allocate_N_O_Box(size_t,size_t,size_t, Vec3 const&, Box const&); /// Move grid center void SetGridCenter(Vec3 const& cxyz) { gridBin_.SetOriginFromCenter( cxyz); } + /// Set the grid unit cell + void Assign_Grid_UnitCell(Matrix_3x3 const& ucell) { gridBin_.Assign_UnitCell(ucell); } /// Rotate the grid using the given rotation matrix. void Rotate_3D_Grid(Matrix_3x3 const& Rot) { gridBin_.RotateGrid(Rot); } /// X-align the grid diff --git a/src/GridAction.h b/src/GridAction.h index f58db617f3..4974885528 100644 --- a/src/GridAction.h +++ b/src/GridAction.h @@ -46,7 +46,8 @@ class GridAction { MoveType gridMoveType_; AtomMask centerMask_; float increment_; ///< Set to -1 if negative, 1 if not. - Frame tgt_; ///< For MoveType RMS_FIT, previous frames selected coordinates + Frame tgt_; ///< For MoveType RMS_FIT, first frames selected coordinates + Matrix_3x3 tgtUcell_; ///< For MoveType RMS_FIT, original grid unit cell vectors Frame ref_; ///< For MoveType RMS_FIT, current frames selected coordinates bool firstFrame_; ///< For MoveType RMS_FIT, true if this is the first frame (no fit needed) bool x_align_; ///< For MoveType RMS_FIT, if true ensure grid is X-aligned in FinishGrid(); @@ -81,14 +82,21 @@ void GridAction::MoveGrid(Frame const& currentFrame, DataSet_GridFlt& grid) grid.SetGridCenter( currentFrame.VGeometricCenter( centerMask_ ) ); if (firstFrame_) { tgt_.SetFrame( currentFrame, centerMask_ ); + tgtUcell_ = grid.Bin().Ucell(); firstFrame_ = false; } else { + // Want to rotate to coordinates in current frame. Make them the ref. ref_.SetFrame( currentFrame, centerMask_ ); + // Reset to original grid. + grid.Assign_Grid_UnitCell( tgtUcell_ ); + // Do not want to modify original coords. Make a copy. + Frame tmpTgt( tgt_ ); + // Rot will contain rotation from original grid to current frame. Matrix_3x3 Rot; Vec3 T1, T2; - tgt_.RMSD( ref_, Rot, T1, T2, false ); + tmpTgt.RMSD( ref_, Rot, T1, T2, false ); grid.Rotate_3D_Grid( Rot ); - tgt_.SetFrame( currentFrame, centerMask_ ); + //tgt_.SetFrame( currentFrame, centerMask_ ); } } } diff --git a/src/GridBin.cpp b/src/GridBin.cpp index ca2f7a2dc5..d006fd1d75 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -99,6 +99,19 @@ GridBin::SizeArray GridBin::Setup_Lengths_Center_Spacing(Vec3 const& lengths, Ve return Setup_Sizes_Center_Spacing(nx, ny, nz, center, dxyz); } +/** Assign grid unit cell vectors. */ +void GridBin::Assign_UnitCell( Matrix_3x3 const& unitCell ) { + // Save the grid center coords TODO should this just always be saved? Can we skip? + Vec3 gridCtrXyz = GridCenter(); + + box_.SetupFromUcell( unitCell.Dptr() ); + SetupInternalPointers(); + set_voxel_volume(); // TODO can we skip this? + + // Set origin and max // TODO can we skip this? + SetOriginFromCenter( gridCtrXyz ); +} + /** Print debug info. */ void GridBin::PrintDebug(const char* title) const { diff --git a/src/GridBin.h b/src/GridBin.h index 5050ffe70a..57a22f7ff2 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -63,6 +63,8 @@ class GridBin { SizeArray Setup_Sizes_Center_Spacing(size_t, size_t, size_t, Vec3 const&, Vec3 const&); /// Set up for orthogonal X-aligned grid with given lengths, center, and spacing. SizeArray Setup_Lengths_Center_Spacing(Vec3 const&, Vec3 const&, Vec3 const&); + /// Assign new unit cell vectors to grid + void Assign_UnitCell( Matrix_3x3 const& ); private: inline bool Calc_ortho(double, double, double, size_t&, size_t&, size_t&) const; inline bool Calc_nonortho(double, double, double, size_t&, size_t&, size_t&) const; From 56521244d8d57cfa5b5d0e13c1322aba02305ea2 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 24 Aug 2021 11:21:34 -0400 Subject: [PATCH 61/79] Add test for grid rms fit and grid centering --- test/Test_Grid_Rotate_Simple/RunTest.sh | 35 + test/Test_Grid_Rotate_Simple/dry.tyr.nc | Bin 0 -> 56556 bytes .../dry.tyr.opc3.parm7 | 279 + .../tyr.gridfit.dx.save | 104820 +++++++++++++++ 4 files changed, 105134 insertions(+) create mode 100755 test/Test_Grid_Rotate_Simple/RunTest.sh create mode 100644 test/Test_Grid_Rotate_Simple/dry.tyr.nc create mode 100644 test/Test_Grid_Rotate_Simple/dry.tyr.opc3.parm7 create mode 100644 test/Test_Grid_Rotate_Simple/tyr.gridfit.dx.save diff --git a/test/Test_Grid_Rotate_Simple/RunTest.sh b/test/Test_Grid_Rotate_Simple/RunTest.sh new file mode 100755 index 0000000000..5ec46784bb --- /dev/null +++ b/test/Test_Grid_Rotate_Simple/RunTest.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +. ../MasterTest.sh + +CleanFiles grid.in tyr.rmsfit.dx tyr.rmsfit.dcd tyr.gridfit.dx + + +RunTyr() { + INPUT='-i grid.in' + cat > grid.in <bTX# z)_U52dk6?&0PrJpS+F-{)lQ{!`y?yI8}JguRF7#($f! z+wY2m?e{zXK9f_++2V6!hhPV$G=BX-6aD4cl-ao{!e|s zi~N4RKV=JrV>vrFH;?rjU4@qW_YS|?`uFy`-0$oDuV?5bbk7z~kAM61cb|P1c46z@ zD*WlQ&ECb$ZlmYM|5W*J|NTDs-*x`mPJg}E;6HWF{QqB2ev6&0i@mjj?e9(%>iNxs zZaV6oJMJy49wHq7*Zq6^e*eEY_WM2lyq9qJ|FuEs|CIkNc7l)eID(IlyN~)t`-htTt?KAL`1Dwh32+hC~FQt+Tg(` zw+h6*)Tcl=pMw;U<(NUZ?yR`ivy?SjB(Nc2e&Na{CCs@0X zsG2M$zMBbG%(;?+9_y*}@@agXP655V;}UNq9>SLP$m11c+NoUc*__vzyIfYt4(9L_ zMq=_Mi3?EgM?IA`(`UUK*um>gvb}UOxW?yS8FA937XKOkY_|@3(q5a$F74h#D!6mZ z$Kd&#N#8^|BeIFR@O~w+Z)@R-43?15dh7WKQjR1eWezJ{5=M<4S+L4sa*WTVeRQyD zEERcAW!k3rbG5hkk_YmMY|qLRwyxwUcTy}Nd7pQ2nd`+Q^XCsT#A+6i+83%L{$BQ@ zWP@fGs&=8ej-}P)Es|LFZ`55RaHVyx2eO`;qTIhXj*cCMOv9llc-x5sM-L+DNE)if zg@99ihnPN!sP$<_-NdU%Tic2K6GcLw&qG?}UT}j$QKK~&dHc?we(QCVEbN2$faPd> z+ls8|eUNf92~CVMGL@bq*ZwsQIL9M#UIyX{EFtMN1CiGLNPN2;oY!F_@?Q{a%R(Zx z8IeMH--tT!y1fx`DIZ&&ZAOdnTV#iCh3~g4G!OlSZ0;=F_dY_ir7TLGT}Oz?X&g9R zg_;wK5pYol2XykVw{st28_%O)KsEM7^haXLainWLB)wmaBI7RhC1ck=q*)~z+=^EY zT>G~I;`($0opOvNeL@HEGP0ZbnT?m3&pom^dg(MX+R>WG*R;^&V>juZ6VUB^AG za-);4)$rSOOvt%uYRnFsc~oT~Pi_`gwX`0vB&kM+*x{=ma8nZw($*_4xv_iuFtx*8 zlA?(1k}vAZ$@9!<^sGh>7c8wq^8)+O;E!e`z49Y>e5nbYIK-DVU$>!!ySa#RTU@zl znGU8Sr+_BhE8}gioo5QHZ?H;k`$aiTMU1D`HRk4(HAG9{94UPFiyhn?#x$zU+XG_`@)@&Ao!U(7OwL|K`XaTi0FSO0AqGa&5bzG2j;VW^_aG zxk$O_g#&eF$hszv z^yDa1RQMvxFdJdQI8%LSG15{Z5WLR_g??9%I_NYa4?jY7#5|;IdjT)sg~;ptCG?#l zJii=6+S_|bd8~j9zf@4Z@*gC1?+eoxswiF1i1;0{FijtUJlQ44SYC)t*50Uh>O|(a zv9Q(fN3(AfvJ$7kufiMq?>|M3-DvpV=mB15750TjA~xncDtc)_(q@K)JF8LVHkxdj zl0-&!*P=&1o@^be(Sw~A-oY0tJ|%q@_Tyfz`av^Fwz8H_R9N3cE0QCwi&R$$enxrv%6614>$fs z-AI8em2J;aE;A147Cb5=ccE(94a7hBh$`nB$iCf-jJ!^PFWJaEW`*1|4*8AB$S|ov zp87K6{rHaTjCz#m=pZw-3EAuBA>%{^^47&7CT2A9ewHD<-)n?xtw4r{ACe}?Ax0q< z$@+beI`<^@>|TwG&OL~)n+vb4(nywRLH2Srcx>K*f?-O?3|xb?_qL;;yD8Gr&tT=d zRAjD_LXn;}cFom6d7V7U`hJJU!KbLb9*L5`HiYR$qReABDo$QPdK^~eZbkM9#1M#_!*vN5AOiN)#LWbi?C_MY`*cJajPyz_*5ZXF{MrKwJ% zgZm~ktBx9Shs>jx$dEj$6tt6eEUcI0<{zdCRvT!9+J3TNKq0M(9Le6s9e#0e4av%0 z%&p0sPt@Jr$TW-LBG^@F$2B>S&KuB1Dkx;}%s;CPB{ zjmacotc3Pj>_%@fA$-KS73>QCHj&)vSyX)8lAe;SqJ4+$qWu;I(=pRN6KA7aI^rv$ z;(Mz4UC4AH{^rOZTQ^tW%3gIdM7-FJ!t^a@Ebv9tjbN1PenfT0c=##qMZrfsG(5Nh zFV$lx^p8fVUov(bK7p!lb5K1v3A^8|LVej6<3ED1VBfsCu+v&q4Loh%-P%nduO?$e6t74R!5-rxe4m3 z?_kx205nXWh_WR;v1gkwZVh{aygMTiq}_s)=w#|M=mE_)lahVkQMJ4ukk9J7Cs)>@*$dBUS!X%4Piw^t=6P^tU5Jz ze?*L?ycAuwvZIHTq$DfMbVUid2bq~~XA!dC3U~OsFQaS)M$#-z@(0UvAzB8+s&6&9 z`^|%FGwaEvl<#0CH$}18Lsm1L+oJhCeWjWBr}?DTWClre!7DB(uJ@8$NsT_z{=`d$W;D?s+Jh69Ptu)B_~lfC=w1kG?0HR17!#6A-=l^MH_w~@2w`pzH?AE zdlcD4o?o$&{BUeAx-*sSi-zW{>8uILsbZgWUY<;N5bdd~Y^# z-Aq9P`au8kB4k;1pzYEk=x^{qhTJfeTU>$f*($`=*P!^(1q9_jMyiJ~8LAV>XekXk(fMJ^>`VJumRU}@N@uch<8AWFFN-Nn*~xSa9mFpC zwugKq0^&Rk&taM%o+J){z#k@FPcA}XQtcIuK+1!TK$4yxI z%NaR$&*Jd7F|e3-8dcr4VQ>2cEZenP7=zkSxvU8*B8pJg>WAvp`B-cI5{=ChPykEl zhb_TAt$Ji@Ps759p=egENAB@Ts5cHk#d&$8%y@&T(*~pR+&3gIuZCh6L1|b!N=Oyd zj0DbA_CnzyFQ^zMBXf5mYE_PaRUL{vcL&rPECM6_6=|>PaCCA%__@tN@!h3pSBOKv zCBe6eJIC!kU`+-!WDx_0oBaCwQGB;3Cw9{uYpytaAkm6n&)A$C%im}YCRGoI(2w(~ zIq4($%*}BVB+tv2lS`{E^BVCM#) zUg$H=E%j(0@djcrs}Fa)V?OCtwua7sRz@;5wlcA!7qiRH-Y0|HtLeyqdeU0>hBje3 zQGJv~g2rs8Uafby+bYf^c%w1Zf1=17I<|z4xI3Qjw?UC4j}_CWo9ZYRIEzM&Iz*&B zRGGv@m&o&`rKDxN2DzT&%2ZZ;B>ftBqS{o;WiDUIg$9Rm!Dn~qh(C`$7gyifg|rJ# z{LPU+w(d=VEBTREv1yP4YSktoe|RR`>K~z0`v5B1Zo&GdBKFPRkFqnVFqa;SW~C}r zH!s98J2RAboI-6-EG%{k^QHw`(2z6;3)cOEs@5MUHtGS=F&L#KTTwK@7&9gbe#7u+ zlrL4pj5VHU>~Tu)JIpcGP6ah0C1e~qiXnCD&=9v5N!i~qF6=vs<5LiAp^rf;4NxQ- zg^*1PFs$e}^1ZB)+`0^Nq)d?`SA;mS4RZ{NkZN}n+08Q0ZBG;Ys=dg0D2=5bh9Nz1 zw=lQXhbvc&2G{Xuy1NlxSwPh*D{^YlIa&b=l7VD??S+T5ICdzh-KgtHk-3^Di9_EBG%;=h z?aUcP&o0@?TnQRa0?ys1Ge!rK@-H^5Qu``e9mUYI&oyZNhc;2gMHOAijz%c8QE~t2?8J0Wl6Z9| z$?koJsEtvj5wF9T6QVr2)MX+c*w{u2JqR7>XHJ`{H*kGtjwPoSOOv-g&$-B`H*~3j zsgC$zbjX3N!npD;Hg)0AKiv2mb>9eFNr*m$CH|SZk(+{W2qwd8-~4fj(%&R3w@^L98xl zAy4X%71ao>r$#8b^8tmI9H3PtgUaAz$m$l4X}ijhop&Dvrxrn3v>zF4C=v!IU~2yk zr0qVA_-+d^ikmF>q{94p_g;+AzmCY_a|qY>gvQTWWIC>b{~0r=>)IhzF9P9D=Rjzv<19l6LS63F?mu?96E7^rkAbZ6kqkHiWey_tNo6Q zt&%2BW}o7Fb*|^0cqI_2ACLL1^ZTIoSaH;R6GmPQ@mODhkjiaK+_Tn(MX_0nBOza9^xO-Ig(rcAy? zxt57ExM3$vd*Mqjt|$EJ55K5FV{fYRJ&fxyN{LR8w3ASE560@UJKNLi6YW^MnBOg# zL!OPuB_*j<+@cB7*g+O~Oj>$hsyWAzPRK6PKKU$xOIEwaTb;Axyh7IUzw&%Ybf7vl zeS4M0CF+xJzh+bAsRzmOv8;~xtx{9eBik;t?81$IbL5XL78E{&PS%5H{R_08E_ zc`=lKgd)@UI^y?Vz~D{6!hC!UlKMNM_s=fAzF}15v`eGftBa$&@=?PRM>mvDQGo~c&!@=bD$eiYg8O97cCO9%X zC9mlXYcq;V5$uS$!)T7uPOerxM)YQUz34)O7dQpUb>FyMQS>{+f;5 zqQLLhT1F&Z>m|1m^|+#db;LVmE7cyTLGDez$G!1BNtcxMBAFcvsKL(d)L~=*v!ODG zoSFBU^XYz`&9E!r`<^zZe%IUB;T~cVr5nbs=%!72IdtczIy|J^!jkAf%{-EL^g9ik z{*t$y_KS|%6iL$NHqgml-C3!5LpZaj!CYgv({x6ftB&|viTuSU{`7N>r~;Li#EtXuQ)A z=2hd78M6RmN;Ocn)JB*KbztPmZm2xF5~&(HFl^IeL^SCLxzdC@-U*5==vmD)y zDIzK6CSvAvV2sK`WatYz-U>S?$lXA~+d&9BKM%9A8<87*8~)uxp;090b{km)HZOu| z&P7nh9}%jFP@SZVqkiYPj%9YDBRf_RhtX%~o%s`V`Wzq6 ziKg>QtX#;K6=CLB5ciNL z+%F|h61{je)f*K@2F%$;jxUs@C)k@r)0tt{*4*s;^raOJ@kV75~yv|*b zIzY{yjw0!v`*b!DjB$hRk<(EP8xTOIUUr%#O^X7(fjX_6($kHS>XaTm;EMu zb6oo=S3l~)%U$^JZ;t%2#lr-y>}W{G%F+2az4aCL7!85r;1HY;=COV<@3Cl<8II+p z!SnNL=;j&WP}FFIwNHeJ{wy3^kcMFG0kDeuh?cTaMAt{d@~JV7_1cB#o23wYK0{M$ z4brqUG5^{1$?c1Q)t!#o`9y%AX_nxQtf7Iis{p#L3(YIhUtU0REj2mLWMToI*~ z`;i%R17ik#MQ&svQu>d>NF%|wX~;s9*(9iq7yK%z;RwxC!qnY@Mi>7HVf}`HMEyc- zPdE6szk@h16*c=eBB*BuX17G(l-CtRUiZSxFRHjO$&5T$w~CH7?MC{Zzr)8n9V1tx zJXqNlhO^WUqC<+eGNu=r*zQgL@N=H-qi3=&Gd~rTB+=5Vh_UZ+(%crv&e`QB4CWy` ztG}PD+qafoI`AM#e-cBiazdGk#S5wavP!PkOlw-yBu`!$dNSSoT=+E|m)LHbM-hXu zAl?c`$)j2B#Cq*+HZNic=WQ{J*7m9)fj>^tr(euydUreSWQYrYV|F9CaD-vkx=f|p z1Jju+QfIlczLgS{v(9{ITRF+CT_oD_{Wful8bE)|IVI{mZ$;K?9OEzUxy}Us+(@7F zHsfw4xJ&vuPp5^JMs!|AfsXj~(~Y0siMvqH`2V%%{o%&nDE=J}GT+nt^# z9|4Q@6dcLw1IH&CFgk1s$&ky~U`ep(;&tpx=CNl)3@qM=z%>Y3+JG$BbA~uz+XK5b zTwrxL9!C#6McA@yFg&mn&8vM76Yvn&?Tdq7tPu6^G{`4K9A7Izs*4ilwv7RuC(Lo* z_QuT7H8}j`12W#Pg~nog>tKGO6KW>5Xq&W} zsju@P+4&W8gy=JSao8$8?8L>>ow2W?ytrW+hl+0$aE0-Dz#yiOfpJ(*6j5Vt_)R=KNzMDuy zH;Jvm3=;eDG4F8LpKFYZmh_!37KI-4q*5A+{Nz^;c}^nB%lV`;>!tgVw1>u$mR}>e zu<>o=;|^=$apwm0d?3x$njB+$`~PYRzV1w?|0rg%yD!uczp}DPjXcwZEnWD3`nKY! z0#_Wbt-=De0_>Z34Yp=eU}E$HHBAh5)EodA{0dcfe6g$20}CunP^>!>Atj}NS}7W! zgi!Mi7)RVi!-I>lX7{u+E3@yR;sJX}>`Q<67Ja~qBM)*$LE5j&*&1kxF z9J#*tp=2kInuObe4rqyi@_N{(U4Wwgb;3Adj*@~F)Fe*E#LMw0yx9Z$%(`Lr{!kQ1 z%|_0XDbO}fLH;5c6li8Z{IWkXVoH$oW+8M3oka1{0f?Kw2+Nf6Q80NWw%@SEq(UKf zczYh4ci)F{UO5U3Uoq)pl$hL-BJOr{G#}+y#|H%%^5x=vqUw2{c*V{&%nm;feuZuv zbuYU>21x%T7or+y`KI^GuMs!tw3|<<_qjpzh?4?0^IQb0sgln2Sf)o`-&@R09PyB& zJTam+8F1aAkh8wIVg$pvk@7caZJ<`5<|pAWQpVH?{q`nWnd? zX&=4TkFMIBz^$_!N`1$?A-;=pSdBg!{DRYl+~bH`=BM`2=UgyMrCspy{d=**r%}U*%!6R`H0Vug-L8bR29l1 zaoaywkk}Xd)8i4) zX+_?!UlxemS8nim{SI@te?aMyqj0slh*?^bQ5j@GKkhw37TJdp+s(81Z88^VT8bOr zyYDy2hYhDl*o+rk;2Kj_cHRPsZV}H)jR+wj_GZ+;DS$bdH=b3y??I2$Eu~3UzA^dh z`m$OJ=Ta%Bk$m?nyQxe~uqbkQCfV_F6_IkzB&Cb|$*%2A?8x2n1RnCSl9R9-aLgg!LbOTAz3Ch~^; zn3UW0%#+(&>3#pLWYjvrmwm9r?&8}+U0B_Pd;f6bZxj=OD`^V>Z|y|ncJ@Ki7J^;> zc%bB*8#05>U|r!Ql17Z!cbWL9#!_oV0V2rvW|PA?3foe zU64k3&O2behM%g!Ml)X8O#d7aZ|5XLW4#!~@J^)Sa9jJb@5t{EOpxN;ysuN70 zIZhUbWfx&zb0j83>Z0EEBMuC>g<(^&(UkN+huX zKNJ-&qcBh#wMTnG`+5Wlr~E+O;|j2^o+IPxLL_ZgfvKPi7oTZBY+6sOIvI?b5s_Tr z;U46upp6*My3gnG?et6IDms1d6l(Z#G_7oZO1`}?qN5_i*~{I7X|a(uL$lrJC6zCd z$%`EL)t8mnMfMB%flEVJm8a&MTE!f`kJk$BQpIX6xL+nmYbTNI)+4CJi|$;miUUPU zFMh_>-o*9IXC^Euo;iK%6Y-1krM@;x`J;VXGOzf-RTPP=%^Ap%Z-nz8b(DHJAlJYE-s3Y+Wmbyp zEHjt~H3@OO7sy?H6Q&kLXfPHyYT6z8ePdDFau^wn(wNnhii-Iv$hJNTm1*iIHZDNM z$y?CBAo#f@qmZ%91)7W|QhKQ)o9W~ zyLDD3EB*5nXXr4D8vU~4yPe5lcXE^#RD`er2CEsbFEMCL9ABP-%4&soLFOyL2K7j+7vE-%S|S zq@i?d0urPrV!_r=Ld;QuoK9mf!PO{u+#R`}IjHvUCHNWFP`c6<`ipxZ^WH1etn!1# zq3uXrD~*OlKOssI@~Aw$QEH=r)$%1m{?Z0iU7)a?mWTxV1mp@iERIe7$Sm|muG3>| z|M(hdwRePP&xQNPMkGIR$CmA9;nX`3sXg5!mS2sTA?tm(WqQZ?vAb1SxwIqf6Z2S7 z6mG>1=Co*h|66R}o$*AUfH=u&)BU%Sxhzp%x@%c6JGIDx&+#)NP8Y!UoBoZDdYi-_ zX!jF|ofGKTedD>iCNkvEp*i&aDIfAGlP6MxC-7F+%o%O3)qG!@c&1{-M#g`2B5C%S z&h5ImpVxYJfKl*U&D0IjV7mK$W{S0&82`5)=$LkY()~dvO`UOq9?(`~sv~STONCuz zsvXBHzR}1|_j6_k+I!K1+m_Hq89x&FV<8*9Y%=#$S;Cqh$fN2;Cz)*luj#~Vd#Pum zKbQT9aO(Qkbi_ZK)Sg(3@4``CIQVal{ISJr1g_ZY`5`anGtxHO!{yxxl$;R!(VoNL zwzL~kbRCd3LIyt9HzPH>Cz9)D!QFQ!;=6xBq3tBfB;Q`yAUWiJw6ZH6H z@EbT6;jv0rC97VdrDOir_MA7)WNO(UG!TSfI=|u@Qx&w&orH0i}wTRpG4&j_VIq5H!T$#&C z^haON>1||3#|2+yn{SI4%VmVvX6TXj%h$;YtM}x=_8`_zS4tA77Dswsb>T`KH}Fw< zoB4@Hy0aQ;=eb1Gkwu%#X`IV3(S<$VC9P3DoLtjX$=-P%NJH&tCiFr9cNqq(`v!fQ zej|YPGPk9MZcDY>C7$yy&+WmbE-m5rX1(B23ggJg>v?qT3I%GI;!Fp}x)5m@SKj8# zPdaSVS>pO#MA*Ea%*!!1wfnt{VD4?0N99#Y*z}c_#7=UTybk%y(9t(pU5k}M?!s3| z`ajkpt@0Jjwm}Ar#4bk4)uuzx_r$=l@)SOJLTW5;c?eh_9W(%h#1Ed&^Lc*!7SZDSTAr56oUEmFi zYoQ2J*^V5Up|D);0bjrFNW=qpS1TbfvJx565%5bhf*0q7B#{hu%0|QEdmW-@S|GwR z9`2i0ASJ&F(ZA+nePuP`*C!yZ{208N)+1M8HZli=z~jjqF=m$$WL*NE zP5&VNyBY$gPNDNUU(%v$mqgXWCb0SSv2^6<3w-0z0W`PcH0^mlhF*`!pxI=+iRMr@hI{i|8E2&;A!bexM17n#qv1oe${* zdR#Qy{4}ThkJidP z+l7a_u;p)#{ISKq^WsbgRwLrjH>CDc#G*b7f@v=#54OWbMOy@)IfSJ5F4(qA4Piz$ z$QafOj?$Lc+9_yeL)&1pW%0n2EK= z@(`Kx5L;HIz|x@sAtU|~a%_WPS{aV;c?F1=-2j75X#}YBMEuQXSeZKvanWm#rJaKn zV{RZOD;rrf9g9r%A2hHKf*_!s_i(ht^c+s<;#rOkgW~e*OYH$@{t;1BYMscmDc3@ zm-!05X&99|UqyZ{n#U?;UE-XZI=JylJ-F((LOk)ND{CU2M+~hmGSe4I(SoVkyxE=U z{F=bQ%s(Dh^ttyMGVjhw(!22^85y>a1hu`C{M`AGd|ms2zc{{zP5Tf={ zM;x_FzsFsuJ0bWdRxgW~)m>=Rg$w_1<8Ku25V)dmp#&S-F^K#c1d-NKY!ZH>5xpj2 z<;}Cg*iwdsAqp^6n}_v}S0ZCwH5_*_FuEy1{IqOXZ&?H(n+Yif*I;jCkA;V$5%y#{ zd{$>-X>})(2E9bEeD?N(*RXba+s&r6pZsB3pfrTsG|!g!NlCa%vsN>9CHI&sN5y1nl01zV)<|Wl^El^g zajZeh8`it@B(KCBV*~pXB3Av>Ij7PMaz9-ptU?=x;qYVj}{SRqb{gZxcR}}@h=P=gJKIBvnSE>=WTc`gf z!uNWdN}igk((`FnT$>Fglh^2x&)e&0h@lGAHc2AYVXtZVTMNn+&mml`5*gmQj<#g9 z6MLy!%!c(j#N^~@F6navm5Nd)lMip#5#N-lb#c1Wg@PvcuigGPNB-Die}OB$nrC2= zVTdGG8+c{bLH~gz5*lwK{0R%Qfrk+{UWg~R1!74bd!(q0L-t&=_6(Bdzk-zz2X<+ghr)wn zu>4smT>FNhBy9#P<+sCDuRki)?V!8tC$_e&$NnmHh+SU7&G{{wT>4-I{{-%{hY9}g zC#b*77ser7RQ)=EDeb!u9IK723zpFQG7%v=T9D!X2~%HGAu_uMqOJ^rbBd5(KBNlq zQ|`kv&m74oMO6MFnEQ(FNX}t9R>r;;4Jf3VU=OrHAQ2dOxZ=pr!Oau zEDdPJg1vN#nKP5Yq|zcark$C~XWB+GKOR`qx)GR$L-Ib^0@6bC%U#vW^Bl%BCS?I@xNOKns3;pvJOed2#k3-YmnD)tdc5ot{FA*N*7h$%*7zO!*5qfwDmRyWPu7wMtFHXa9vqvZv z`XIFZCNyQYB6Hmage5M9ssWFJ1U2~Si=nnwgw*d^i2Fwub8J5#G582#?y6w!Eo+2r znu3s%N1*XZ(0Co2k+RVdbG-JzFGv;%&zED?%kkK>WZb=MSiP3ORdq^H6#03N&U5dHOz4$aJvAoF+4*v|K}uo+{?N zJ0Ofr8VLKk2iEyhkaByZ@a>6!O=Bfu-}ht8&z4hdb#F#>)H{j8_eOS@og-^(Xw76_ z2%x7Xjca+-;Z7c3*Q6s~ou`)q`Y@ui-^qa9B2M-nIsU85V(xh4a^~HIB+{l}N6%@# zr41ANbGsj_iEN&&C&yb)gVL{MUZ;H%I>1;@`R10Ztj%*jH7^JsXDIdrre+ zGDWGp6rxWLfc=Ovlr1boLS-dvPFz9l%nU@k6v9M41GziF3ZL!3 za?NY-pP(S<@ZX`MRg9RQyRc9360}-d5w7fk`g5H??=}QHwnLeZIW+H0L%P#&RDWNN zX)Z62d3GFf&7A0$`Ao13y||>sIczl z4k=I&6NQkTyt>v`YPx7BaSL0*NNQY3%y(60aO+m)u-9@{&8(D6Wp|U{(M{yZ6jM>+ z<7@o9dEZ#ODL?4whhDt8{}ldx`ByHd;VZXa=_Z$2ahk{^FJ&%#Y|?f+w}Lus_hNb- z+(R<0&k*aYJGdV^rRgD=e5x$Hh4_z5V$I&1BRW9~IHso)Sy~iKFKipm^{vh499P$dMu1bfRTiegEYevhny3@C@>Kdu6Ov!5+c}0%7r>DsV z&bY}PT(_EJ=vI>a+H2gel_BKdgsqI>@F*cCL6y4}7bnDjQr^mF>vf?JJN(yH{lksF zQ5+|5B`nki3vzoR<@iqoUg-&=E2k0nYZMY2Td`y%i!=pc-G=Nvu)^Am%)&`XJKqn+ znU@f~`zeyIUV-hIFhn@rN51Ytm=`WajP(?xe%uJ1*2xGSlY)eSv!It$4zILI#Mn=U zsmvp68#V%QUwxpS7XU~9?}%!i3N8O4to%9-$;wYKc5NG6v~3X|w;%np@?qntfbi#* z=(qADY&Hqsmq}kR`uJ7&Ty96!%uLAp^nu^|naI3dg=v@XBIL6pa$jgd<=acds2d@9 z?JU^z67n-UdmuJT5pI=2JZk1%?LA-OnT;`OL~FbWo$ejYHBRUtp5IKEXrpGTe?Onf zjGoGdK22eM?ltFU?7T)p=d_Uu6=}w5$S{6Q(?K$2;whpxXg+Q6IY}z!_F_ve4dB*2 z-cDqs%gF?NbLPRMOfLLWCATNjgLySahG~3f!y2@|6xE+TMCK&*=3*z?(v$AvIpg&& znY-nxWPkWtx^i6{*>G8f8NPEIP3hG@%tt74wQq*7%U6A2RR%m@^v5)DH+&{*pZVF$ z%9(#5QDr09)U!RvRm%+Sq+cp24oYH2zscm^uqSBB*UgOe+5#GQ^lr3#F;3BK*o;Yg5Q3mrRWM05%oMtC>a zd=dPUNC%{|)`IqW9ig-B5fK&y>qEBi8@3Zct}|fjs3K^1=7MHx3AaRH-kh$7xXq`q z(x(Wn+nSLe&WEm`#XI?qL@ak28oNJW+Y}&0`2j?IOJTmv1SzZsroQS2Qx%GIyIC;& zH53b9e?qQTs-WEkLnBvMb9CDX^R_5rmRTE8+q7VN;Tntv?nPSlBDm@lL1%Ub633}v zgH|%Ep4uSp-6(kN8i;krn-P8J6P!MsKw|1=#HL)r?(in0WR7IkTC@_Ao|VkgNp3Vc z(w^LP&?ev8LWqU@4H7^14UzK=W^>i=^GZGs*`0ox%<7hKVj3MpCoGm@J$AX$cNO#5 zK`-?wE#z8uoU-NnuqR2iQz$=5FIjRYc0VnWOC^VU&g7QFFJUL=PT^;p5ng#$Fp(iP zd|!|4)MNe|Nw9o2udMo>lwR6TRgRYdY|=BQ-r0K!3iH7V>ABi5Z(jnui21Suw9@|L&uC#TB_sN8M;X(S8+ua;1VE z>)%9{Wt^ni4Zae!c!u*V>* z)SSTVQfat7&_%x48Npw1gwq5;Ukh!9iS=2mel!%x>psKS&mT@UN06{@2o~4PfS20> zBz`uAod=Ii>n#Lb#u0|OjWDCn5ZxG#xi5dg_?~BCQq1oDybT zdV#ROgIJqjhzY%cXmJBpN0&n1SOw8@-oQCC1&c;JKuL{1EHllqYxq>;Cyj&M8aD*F zv~rmri-~#Q8}hSUhkWVpO3wLN^1WJjFlM?lq1B-fdl0(acIr7(%L(hf0xPLLR3p4-b z$RAt$dwozsK7o>@9DG}Sg`8GHOgv2B+jBXxRwZCc$WVCagdpGdEEH=};L-CL(q@%I ztCYjWvnoike~$&*Zeg?0J>)XB5HW(^s1}a6<>xTNTLr6oE<>Vd2}Yh6g5{eYAakT5 zhJ<**2s6Ks+MP;#Y588vderC|W8HA9#i=kPi1G6!=5u7&$3m2whjZ!iS zbu+l=>=q- zx-w0_K9;Tueoel~y`=TZ&*_4g8me`2D1ZIKFjg(loy*X;BMPbP%YFIsohz5#N}86P z-$}DXEV2A|meweV}47{4RBGOmr4{;o92HZqQL?ZOJjKkU|TaY+XSOYfUDOSqb zB1FguQ0XD$!Z-^W-t0&W2s#3b;TsXNJOOf(k7He59|Wr0fYjXHFw|Ly(7tbU?piVM&_l7Y=HEp%R_J;IDORqQkg*14Emidnfa@N|8Kk<||{FZd%igwKGI z(haD3UBsSoBQVWyHT1V{!1l}IpgsPCkk4l;terjzy;uYIOIaady9^eM{ep=4rF8wT zUd;A(C$e&WD@|Q$&(C~!oZI*ABpvioj#{3srYG#Kl8=v`5u=zn^l;M;zS}@Qs#~PV zIggsm`qhqQef;ke^JOdPx6li0kHAP`u=Zd};w%~NQebz=`rQ@X@loMc4qrpkc8p*Z zB3yWVFExIANdVs?T$=96mSNOVTiK2sS?r8QI&}C)WfFYhAT5h%V7}aKWnS&bU=)Vm zBPP9vkRAHFse}4bzWvl-61RFLHRAP{5V!Zj8iPCh#)BUTC5|!OSc3h2yvl*v84NJADri4&1AuP;Vk zIsx~`fr5Wpqx1P#8GN!QA#40;oo6bRaBmWP7tvjv`@MzO!GdHYNA}g(FYqy}6-es{ z)G1C`i9orrh<8-e`DCAkxH~MOMB;G`Esvl zv7-kqc{-bWJTjfy%^XIbyBkUjehm>_8-AEioRrT`>@4Sp?Z3@Vennabe`Hy=_!>@; zu_P7`uhRXc#hlgwBdQ$BQMm|b+TCg?yUk!4d9yW>=z3-_-%_lY8N-}NNYxpZ`SzJc zTxq0=RWa1s-eB8s{!}wfS{g(9d0TRk%b$o2 zB?y}S*Q_-Ap=MpE(SD^O_r3^ss21Xk>oL1( zAi^$mBH`ReC@(98KX)Ao^If6xxD}o`s)(7k90Lk^BG}6hk)|)uU6_mcMJzL*QDb`~T>=?r1LG_m8YnLKzJb*%C>S_j5m94-E~? zPifNLQ_;@ed#^}Bdyojv{ZJ_l4QZ#Tz0*$m-Jj35{^^|GU$5?SoH`xXxt{yJuGhfU zN@MJ3>Wn4p-(vZzL@wvdVeY}o8T5J13%-NO3mSF0`{0C(wOnJ^F=BV3hJ-&HMuU5F zqWc6%|3 z)3aG8URRH)ddxkcdFmsjE6dOG?yr`LqAY_B^Hn6d3rgs``FnVC)BDoJ=4Srv8DCzm z`xo)Tptdp-9^v*d1BVE4&tkA`zTq0%ERU= zVqLH=Eji>ts$T|DpARP7?iuH4^=Mb_#{OEdZ|hAm>qs4`52)iR()Myo4NnpKU;A8K zzibTJyGiALxbgmPeDkL^{zlh-HL59+CT8TTz(2Yc2|qou zW&7ea@V;sAANQj`I0?6E#;?`AjeN&Za9J&2>0vMIZ+QdPCr_}&J^;DV3b1dR!L%Yb zksA2}7W<13a5frAuR~$Scn51*bC4J~4Z1rQAT)#R5f!YVxyBDcdF;)62hgYuM*Q|6 zNJ{VJ(x!5S?UjxoX7)grk3*x7aIGhD($Au2Vg^#CHDJdiH|RcM+O#u1$nUZoHaWcz z*YXj&w;jeHt+7Zdw!qF;ld#yp8O!=#LEeJNm>04DQ>h+NnYo8JkytTu^kW)##efbR z(M(GMYKi|pZKTJvSi0DHoAag@$TX=p|=d8;>{FEpc6)R{*5 zT)j;chFqb;3_Yn()hO1j3S+hL#z&32{u>#G^1n0vyGH(;U5~L^2{16j+6#;q@JJng zYSmb)!aPqjzarXwG1jb)M_|Z7w);(l-=NEg;EfQw&IU8?4#TF@gNSs^#x$o0EQ<_B z>N!75yE6cO7X(DVT!GPndl8z&^q}8I!ewAjgp3`D%?p;p#d9+@y$?b_m?vyc^N6mx z0v{^C{K9KQ&&We~&PUj!a7ZceL8w2NE<}fYqc*}{V>WvOokN!23?$UJz}YYxX)}zF z`ZyI%UD)i+neD;T&tp{77Q}b8M8=+Cc+Pu=gfg~sdZ&iK)t}(ASVUOsI)vP~jrj#D z=*L(c+PFcDzIotE3LUDX=&G$!PUCR0?)gk=n6j0Wd*0$LRv(fU{%Ry6x?Cj5^WM;$ z-b|Bvt%{u6I72cr?ML>%P9V>AT2aO3M1Fj24e1|RPUrKw;-%7PV(7kQ};NI|-u7bWf@MTRfeRv48dR^s+a{W*j*AL-t(sHx^;j%Bk&mI5N#^2~l zS*--k?t*{jyg%$-)u-;x#N7zcKNZ4)fh9gY_@A zCq6g?(ae9TN1rCfYa<9f*o3Z3N5B2`5u^o#LA#|E+h!Lbv*%2xu6c@rWrwhx&G$O6 z+3>CtlaX`j6by!*MC!&_C~|y_?i*erO_%AyfQlk^S&TzKzFsoA|F-|6d1vg_k=>gI8q#trx2ay;|t zx#RA{aC8@Ln~cgn9~mI>*J=n^GLD3DhiRVx8?pZ0B68$b6qVZE@H)QFs7)6uI?^eM zOF#LLPWlv07H{{Z?jAl;=LuOfOfH>IebZ9)_=_&hoY{*m(K*UJ)_u%X?-)%C8lAaw z^Lg3KfNxc1r!~ZDc@yX{LpAQh+;np4UZu1sV6N2n%0#iY#EvGp?&pRFn-W!3GcsB( zUP?I0OGYZTBz*Prs%yJTWglm+r$?9O@a;H1;xpBwNfa%DS~Dh%R)SB$ z7^EJ3j|n4wU`6U?gf}_C<%SB@%bkb6;|2&1>#;#gKt$FKI8+v5$<7=^A0CB4BNY)k zbT%Riw}H=EfcW`J2s*I_qx!K~UFSx`@+M4&F%22#64~rT6I}Zu?*tG;CbkfQX;v@aozLUM8vVFP(*XUCv_qxdm0_!^g?gDul|pPlNf687aI~ zXfL9bFjx%Q+f8Mu^w! zH;{l)(Ul7hRMT#D&SaubcX6b-8~JgpAKha5U9@j0u4>el@e0GflHH~~I8pBgiT_n9 zPHS}KCU@ygmnshD&K#XbMtK&vxIVb2aHrpd-)Qn19sbnD-{|_UPeO9=I!x_gjdi{O z$Wm^_bX^Jl&r}f`e-%TW$6;-_4fB6niNW0|d{fwW;m3NotyqSTPHaZYYHDodV)lJu zZzbhs3~0_q@UMRCyK)9@C(k18q$i?DF(%(--wK5p2n~6Uxh`zJYVZ(=vA5vq{vNrq zK}?q#fd!$-$oHs4+T;ohN$!RGbMeUP?7;K`9hqNT9P-=`f_rrd2i>iZzB~l>>}|Yl z*;-@<+(Dn=YmjFZgM|AAu=`ZbW;)-HuwMq_vI~ftG7AxM1rS;}cn2+ke`F_&q;{Cr zw=Z4%&YXQOzR_9cxe_nll6m>QBcFEP5W{S~(G_0@Q-_fKeE0}ee$MI&VpZ(Oh3pW? zn1+MoRu7qE^6mz`{e1!b@a83{eY!=a+3e0ADNH6i&wV6sbU%m(N-DXybA(i0)S>s? z>?GM8f64Nyztp(!CJ9RO6$#nJwfBA~g>EaSIg$Fj#kneR*{nT;UwDgFogGG2pB+dI zo_7{YUYqk1j-BPVJl@VHl~u@=<|uGwDbK17$XiJ?@-fYCwct*rG>O|M4Bf&8c8QMKzbEFG$Uo6A+pa7U3NJYL8yK5Mx!b-&ng##}jUQ2{gKj2XRRY*10 zf!@_UI23sUA(s*`V8dBJc5w0?{L*R0Cr8n=4v;1=q_ivp<{?- zGr)<_x>&?!NO4Qfvb*gbEFSlQbGbILYSB}UelB`WE^hOr?wc~DzTPJox2=V!P2S1< zNchfqs&^#~7nOPYh_151=X0G0A8AK-b*tce>oiDHwfso4|8n}^wJL4)4Ww0FxAGlc zsgu$llS%J|AH?vF*<$vLr=)PpIBEI~A8}p#ZIbQX8^qRPCvk`zK)ZkXAoX76U9CK^ z2UVUioFuFx;_dfys(MvjrZM{a#W#J9ix*Y=NEtVfS5DQGiYHW)y$?5un|4;v+Q{+z z(lZx%k1^x82fG!;Uz;TIB4R0bR`e*8YG{;7?>(Y4{(g|xXd;e1FR`BTFXTayou7+36yx{h#* zdf0Sdf?e}75mkHxda2eZD(r`(1-GEBe;+$dgAuCS5vucTu+Q2H;a69?ydPr7yvXX{ z*L?&!GJeUyST-9zeADII;JGN)-+`6r^Tin-@am+maoWmeTAuO+1u*fEY4c}2u<7( zK-7zmlJ`wc(jglozTcuqF7Z;G?AGZRGNbJxku^}>oeQBO&!F5S}?(~ek8zD$@-8rK})ib`u}%;F?6#;+&6 z9vDiU*S1It3Uat>Tn(9*pe1!0Ys(7{d-2iD60b1%GFi>IDOayfr;S6e@-Z8e$d1&0 zT-ZQMTC6%jCiCq=8;q`zG=B%0x_dO)I)Ql$UbYGFU3vO9#{R~vziZ^r+4VZBl`V7u zCau-Owo46I)l!5ROiP-%trvnY|pp9Zx|9> zMqp^Mh{9Jq;wUhV&DcxYdLgWnGX}O##bE_A#BMqZ)9XiZWY|c?f7=L4Wu|dFxD!#+ z&Z5gAb(EJfj$A-IR1YhnGLC&C9P^;gc#g*oe8Pr}4lXVCbWjyp1%E9~m&eb{aJ;rN zRvrm}ewThIUCwS{<2`x1@X?;$=pt}Tr^X-17bEJ)(%dgo^KWxSzp98sMfLi!BV z(c^SalsOJYhUYDGSN2A!Ng*Q6UV_%8_c++b-pcpO(P1Np-P%X7`SfUX=@NzFhWS_( zbro`0<{z zKJ6mfJsCrcOP2EO)-R-~N5@gmtEWl!wuj=knhr#&svdmu*-q}8+(f=pTs^kb*v6>DD>F$oR%|nsljHoKSAetDn0| zOC9~VsM8)&fV(QMDc^^T-rp$ZjY+0C#XYz?W1rLg6B{a?56LFSM!3+%Wur;`eM2&P zQV{KT)|&2ZJy+%bGD}MGy(Jy}kS6XuzFLf)Y|0JEt(K<5U!q;Q|Dygy_H^ov3fbUL zNqo`4m-cgdPqwzI48ErLg!xV$y`jB#$Zu5rje39A$e*+816C_3^9V*OmY_sgk@57I z5XQbA4mqAcdU_qkmuIp^zZR1EKY^D{F={k7AzjW0B>f<2w{XbWA`g4la-1}qkF*~v z;Cjps^;g*Yd#5%AbPd7DnvIB>)DDJ|OCi19hlB0s;tlOzvl&=M_H)uJ|CN& zxI(3x^^c=>uxjOW7@haW$<{(lf61eJ_IK1ye2Hm!I#6FV7}bY9VJ%;WL8psQ_bUtw z2et#6w&7e_Uxc{zgiDJ(>Q3B8=uZJ->we+fi3sF3zQm01Hi#S9E?x4+q#3hu{Edb9 z)o>G?USUmLXX%Tx7c|kiJKoWM3@SP8H~xgL}E z;*y8VBGYXQNig@EJ3Z+(um7=BO6t*pT<)YpRhQIqM=Oq3jWA6m0ZsMdW1pU)-N_aF zShb0~Qdvj|Ab1uy}qiP<_7CdA@#R5kswos+- zsl=)32fd~KxN3>=T=C;tPPA>WB{M2MB3@kK#98iQ{&4pm>V-dGv$+3|X;%Nk|KES* z39FT))5hq{-Xi-tq#(x01l{bLaUd)gNqSCj%w@XYME0g#?f|aN0K3O5U_MZ*fbsy8 z-TR8H(-ClC`=ekfTKp;bI!H3vEwDrl^I1>YQ3w5NA) zeP%ms2(!XK?Mj@Bdy1tSmVy)3;-XFJ&8u!htl^C{vCiYnOj;?Z0B6{90$)Tges1nmPPoDII%57*9cini+J?y`mvbC0| zJY@rQ=%PjPU)|;+Jb#EM%hpI!Q)crG&IQE9r;W2=LsgTm_oaoNU8t(mp{n#%XWA=g z7B_SIPi~*8gY2@6994gOnf5F{&#Tm35WQ{dq|S?{P&MmVvcLNfF`z1q+*AstXAi}@ zDBSd*ZexbddnOR`rcd0VMMH^ys6>j&tQZGj z!t9beJAUJW-?-{eANdz~IG{aV0$=)66h#tUU>{cfnwsU75 zClBD2Cx?=puSkA&5bpcza7<#J>Cw+XTJ%tQiM?wUF%IQhHB^4dK)ihrxUpJHpUiY0 zbqisYG7hIl-N81+_b_1|EGPB{AfDYX4C^#;Y1L$;jDLeJ*`sjfj6cHU2g5?Q6phz* zAmGy!81BkNQ)DHA+kBw4uMT%Nc155=F`U=#!Npg}SfiT{7sCu(4rThX1Z@o2@(8Eu zrXrAOk;d70;rKYVW89dHNgA(FxW^o6yKZCNWg8Su-%sX*wil0oh@ov0hVv(fr4y?~ zC6e)?9CAEvff)bv5(#+MpAIi}m((6q@@r;aB)PMuQq=_~$+1h8{Irqa^~R-hua;a9 zmo{$WHC0TdwePHRW@H7%jt-(Rb$jnClj%eN8BeNX9iy=63M?*Vdi zypL?l6dP&b#789kR61|O%s1?2J|M;|FGUxJ-jz=sowyyfn#6Tq8~vmiBv$lu;}s11 z5Q|+CY2}Lmx;UsO7xQ7HG`eV-xPJRTbVsW)+41rjUD5oD6kYWdLrw=uRR(<+CpS`z z;6z#)bdyxhH6iiMPQ+vQTNl@>hB~{O#NQbB8^iyukw0hGfBoVLSD3)gdq3#$XV^V` zE-d1_P(J=K@*b?j&<|~(+f$IuddaX815s8 z-^H|q;W)#**%Hm;AzM_6^OZ8hdY(jIj7IIfZAg@*!FntEx2)t5+PD!0As29FLq~*c zI0wyq8BRQyhQKq&U^w#!8jTOYFJ2Lv?9bO%euUrrDQI^+3|B4;LujW|*tT57Ew6P5 zWV{>Om-q2-+E&C`t^i4Shil)e5$`__BgM|RqshFQ-+#cAj%QJ|=QHz&e~n4k)NoYy zop^tqElKQtmkUh#L2ITylt$U7@|~;SinDloF7L+;>P_S{$e38J zuDXTl%&(-~5-TM6n%gw!+ys8mU^SAwy|b+ED;KfLH3!;$*BtVEk^!%BgjAI+mlxw& zck{-BMQ&a3y{cVPY(;H{1GM;VA4zV#JK3{BUuyEc%g?&+M2GB*r^b9b;VWS((KE7&}xUFtr6)>r;R)>r<+ zC4Xw;Z*={{Y9;!^T#!D#C{gW+#6`J4LmKvbF<+gsT^Jc54^d$YLXsX~)T&x`w>ZjX zDlfqAYesF61+o(z;IwrBYRdAFzM&eUI{t&Rt&ICpk_}sh9GqXvJh~$LGC!tAI5Uy) zqJ6WVwQ(wr7l$KQ<2}@mUB^YQ`v@GJ>hiOs3g>;U!GHaE=yoo^O}FyPxo>6 zK?wYkpSyfLd>u{8k`NTx1J+YE;f@jWpJMzcd+YvqbYLDL+0NW?{0v-;Ved8hz8LW(@b;m@LESw+EzoN$GoUow=9WPM~x@xlbmSX+131Pa|`MGkVU*gLj)<`?jVgU z0nO_1i=4OkOh~(A?#kq6baAROC2Rb!)+$(Py>Aap(ce5ptpH@)uWHRmJ zzm%UGG@k~vPnG@L(VfdnP$RSTJ8;zSrWn`7i|=r`J?GQ0k-Q!GgS$L9gwBXE<{Hg< zQNM<=d1lev~XPkKzoaT4KEC zylj(3Bjc---_30Q>Nhe^jsMPv|E`fgXV>qnRx)Qj#_$mfaJlywWYcZnRM+C%wO+_k zt;ewBhqzM!wGgIv7Ja+kz>SmaetPf&96iGEh#tnm>G$C*`PuZ&Gb`;JukZu-YVlsX4s=z2S>@BAC1lr_&Q+rAEpGDlFXH;ksr<~Q z8uIhiS?et`()mA+>0BuEdKRy6n(7OmKW^VjDh?xF}Ew|%%0bf4W%TQT9=FkD{q1?i`~ z;O=dJbDPf~E4vVrMoz%>aYqq#U<8Jr%*M5GJrHKJ3XYww;?km-h&*Qnhk0F5S9~6u zA3lP0XP_~{2XGeVEG$Jp_=aWBh@?ZEeA#)S!ZbZ9>FC}dvFT}x57 z)Q|bL`y((t7&RHGB(!m&xcApUx@yP}US8q8q%!)m6t>lw_!4{CGWiABzv>EaJYxlU z?7EifT?mvE9Zpc)mg8bv(nj*`?t00n&m?}fw<6ivqlK53A1-aMb)!W=hq!k)b;%j$ z7IAKamN-{)8ckO7BfF-Y<}=fM=&>H_D0#R@bWAFx+I8XNfn}C7c1=ES)$oM)g_O}L zjc2%d+66S~>mXX1Rws2>tXNgQDTE$qI75&BQlbNuGD$+G{`8v3YCgq$318i-Ol&N8 z&0Rg#OGbO1qbco<@?+Y~r|a6j(fe`JMYo=vMfqhsm)nkc^}PQ{j$Y=dQi-FB>tnI^ zf?Lc3`9BQ%jnRMC$e**@zn-N94>|bnkHtj;ee9q56@i_@ak(h~+lDco!j&2{7BYR! zDyIMaun`Tt_pw}{4G1jC$NfA<>^#YGSC~KLqxFVJylSAgGsaW=C5FVC& zVV+%UFthhl+{n-0eypf4R#q)VfVm zqd!Zjv>Pvfvm^Ci9DbL>8o8^`JfJ|psZn8x6l6AMwi4j&Z!*Fn66Zo(?*Wg88ACTi6ZF+V7Co_Y%hCOvmGG z(a1a+4IxPdk6c<29Xk@^9?9^0b2LJIbJ#xN2%afDKt#YU3@YAr#{;|# zK8^sZPnbRS7?>44;<84=*PqAxn*=e&c?i%Lh%c0RBiH00-Dox*zwu&v*b&INW{0~c zD@cl35lN3{8ogtaTnvtH5ucqt$?v=PiWE0*77x$t!!@igquW)jrTtxxNfpdYg*>qx{Eg1Jkwuf;SCYlUt+@$Z^TqQ`MJ}$tUK_^wrvAnmzj5K8 zKJquZsj$A1%QPL4PvY?L>`rXc8HgaSh4@g+{JIz?Hm=8Wyp9}<1HCJd(A@&>TeGpJ z&o+c9Dx>)=j{=i=M7WK`UDE;-*WW-G%J8Tq4n=kXeAfoyX*)Ay*Kk-qbRhdZ`6JEB z2^*H)!z1tR$UIvFPv)!hq_Z&+-=D;U0ZZ}dmWo0`P^ z%OYsiDW)}4f54x-lEvOCE4cf1kLcMqYV^VPe|WvE?WFp$8&Y1EV`P&LB<=g3`HpKR zlMYlyqDB;ni)4iKuFRx`>WYcp<6ez2skw zY!cn?4x$S_sSP8Ce-M}Zo>80M6CNWF6YjPBwjO|Pf?soo@{s~?l%3(H9j9p zpP!s0S-3j#dVcd{tGAdii`R)5wt`>|cwklnXfJU&DDN?VDs#jj?!l zl{U#~H=p^#u@H%y8-63>KK*wd{dbN0IlHxIeWh?p8DbXA73AOfWBcY#NW3&ckRQf! z#$*wQVVP4ucHG9%4NTu2J_^4!S7F~zSA-^R!uxeh1HG;WQG74F%J9Jvua5}rHV3cn z@Yua}7JN;-(ITx!u5kl=7*F8KQ%7X}vkw9C0r)oCADM}E@VfQ{-)6BKsV6m6?SjMYzc8-8 zEfi7$IKu%C{@_HXfMUD}^a`*xRh z9IQd!jBln><{3&8welpV%pRohxWMUn4iN9OjUuj%`h38OOZ>*wrX<7Ng0t=0Ml0_P zEqB?FNXK$=G*a1)Qmg`b{DHop5#oDW#gWA-zh7xXpf7G9aj86HrjsXQev z*ZrhD2F=`PDUoI|o}RUf9+ zh{;>NNr^#IBz{Z}>a{YLj^Cw0u`i9-56Kl(Mii3LP!lpbw}^J@ysGCyc`G`Rt8hzCmc$l#Qa{FA==C5uYzaV{g(YY%SEryN032YKVY;(KdXU z-5VMGbrEW$f}hN1B`xL*0uJoP+ne)|WjP*;XD8!(Rs^!N4`Xgbj-bG{s9A9iSb1ZG zpmgFjG8cKn^2GDp%WUA)3i(ezU$-5{q!C&aq)1GhHtJ#&4?bVIn8p#Q~(-fA! zSbv+>?xn4idih>M_wS*E;v`|-59T5jbj`|%uk|ABk0BalId!$`vDMZ~8X0UFe+r2>GW{Vc&XKQ0th0ojcNCKL3TF?!>Y% zqYlDmte&83yc_$v`=Hz196|BvGwh3a1nqDeL4I%;isrrrDXA9}9M55Q#}kZuI})vC zQOF-~853S+3+?n77v{olc=4L}Re1)v`fQI-+d=5`k1tXOn6RuQGoho(L#kWbj^g4` z+VhD5cWHvR_yE^0sCbq5|L!ZV>pgxS-6mzu`&1m=}**%FM zwSMObALK%U)=w6%z1O5~Z9}C_tskU8?@h_>z_m1}V1p<>XqBwPYHQ+dN@(<@1bTM3 zxfFlC4<~pAa}Cqe$w6B=&gsWPN#SCK7@*v~LRsKtncq6{JxoeT=gW>%@3tvF#=)Ls z_}vsQ4U)bxii+g2LmJ~uYJ3^v!saahVa{(X`coT!qnjq{E2(du zW7DHGLdOO#Z1Xt|pKL9m(`;|V$*sWpYIQ+1nQ1=!k6``kL_zV!ZbXFmV9t_(f@*FP zfb{llQ zQ$h8C4z}NAIx)|BLD@AKg*($QaDt`K&SNn$Ex*A-Aze@kH$X=5MNGOCAjn^N!uY(O z5fX7sP&w5N8;b-4_R0~I@qri@*pnHi0zDMFLh6uwi)A28B71(mqX#bNP;IR+>hS!S z6gRz`H#*@j*|lAvB^BOWmQ+CJG)kmCLxViL`i+!aE#!?-=aXY!>ZNH@O~tw{0M9T#|(Z>>E=^N#9?U-T6uqf?`${!cm) z7A+-O2W`i=^#q1EhTK zv6AiOdt}GD6wc827s)NZPxL40OK;z1N-LswaCIu-?n$gz5$dG(fK$2zq~lNF08La4-dtt1AFk}R~urcFg~Siv><2J9l={afC$e8xnxBI zT{T8Orx9p9I~`%K&%yEOVnMkd^I^(ff*~0yLVN4M2xzK?4X-GuTw^?J4Nq8WEf!Sd zB9XqkGi=A!2x?P?F)!43kanAePVXX-_tgY_xb1@4+XNKFM!}MwB&gqAgo3k&(e>aG zLDj2?-BoX*{kDBV`z{@E==)m8+aw9fiv5uj{s0>5jtPni!K`ksLdo~LAlJ-%SCy8a z$L+;JyM>jA3%>~6h-5*|Wj=gHm%v>+RFJdZhE>zzG2QzZ+7^Y;9;;hvdN&W5m-7dH z*#sMDz)D5($YOd`QQlW>)z2qHVSfhQmV28XxiyZT%3t7h76yn4#6xlVSr?D zcQ+a0IhsCO70#cZo5c6mvnN^GXOY@@AH}d)Y%ZTv!R?;lN>1PI#@|nf;a7V5(~6oc zviBKVso{=v>NO{y&rImTTLwLs8XBIF=v)o%>>wS^Gx!_V);LF2HDDPXVf8?=(_BE^ zQ(n-*n6F%MR~6FUB!ld^*o6)}@5BepIwNT>FXav$vm};>*t@9PND{Jkyy!5{i9Fn- zLx$(n*H5R{+!+Z&29)gsf|H$ zu|g+~@jsNGfggTa=xl3`D77?@k(PqWYmspY9N^C17F4@2?Q!O1SWIgXl)AC^(1klN zSp7{+p3$&&nj^?HvD~LceW0(vJyD2EWorvP}jpz~jS!nmcmE~R5LFv>vp*@?$mFU&Gyd6A4=pg5Ul8!4~9vsmZ zlw)$Sy|BgQ*P$zdT3|f3Px5zppkpR<3S@VbeS??=wo&LH#31gt9+bVC1ht@21dv@A zmbq9^8q*3NaWS|=bDap)C zO*082;>2@A{lqt7I5L?o*!x3F*I;>woHIW{=p%Js)=@MLwjzbMKXVExEBV1<3=L4( zA+4y)qGp-%$gOXbM9yJ5#iu4z-!`9oI?<0jE3>2<`ZKTPE$%eRPG`9u zN4FZ3%l{9{m=5vZbJ?XowedH)>9M|&YQl0 zp~K=BB#j&b{)S9YJ`sgzRTY>{nkcC0UqEm`D@>AWg-&CBvHTBv7;*yz729AW&vHVy z5&sCCej2h|h9q?5GXyn%c8^(NhHgK52r65Kph_PYFOPt6E(Eoo&B*`J z0);_egf1Id?&U!@mzGooL8n6uO1Q-?UlnwPt_EX~sk9!-Rv!fIuS1YA)*EsfkA!Y* zkC1R#7aB8W3R-QS5t(ZWZSQV^wrV7TfAnGVI#Z#&`Y3ENxr9&KbUM!zsSswN`2D94!(*Vl4@p{eY}F=*3gke52~kghVG^}D{qoJ z54uVvjXq?Tr6#8{KwG@S@)UPpLE9Aa33mP|~QMM@F<)wRyptYLi ze5cE~ygX_qXjsWmFnhVnum1Hy*FiZbsH=5(cWa@b$M&Du9`n&*fh1`8=Oa~qJvu(P zEojfpM9A<=@Nb6*9h+|arSf|Poa!Mf%h zxl>Nvsr=?U{GeX?G~3TEp$ivOcYUW?t?YP*Yk3eS znVml4tYq&>hXps%PTH5niv26d?MN-sWyk@t%0@{%?y!@Nt&b+$i*hdJM;&>vFhjgC z%}!c6$(le%MuIehxQ=&2>8@ejs*dE6s^)oj$W&fK8Z)3yI%zsW3JsY<{C6@gIrC+n z)M+h0>|;6~VlDE@mh-qXi93k@zGdQNzw6}cGZ)gZ`5EyVQ$lC8bzpg$gGpp_8ZEYc z%I$9-LY?bajXdh#dtqw$Zyfm>|M^oJf1{iJzkMaSsa&L(e8qs`uY&5hI7Dyg2Kyxuf@+}&(pUX}eWbmh zIN}8|F8aa9Ih6Ghf9%{j8$Fh12_1s6vHR*zn5eH3RNG(1uF@v7&$bpiS=ZpOVl9+U zEE769wPDBBa+mM-MhF@WKT+^r&E@*+&O(>fjf{&Wx}4K26EuriZY%3midR+%S~la6 zr0eMN>1K=2_4pDbT|Wn%u>L~lEv1Nhxf4AWs|XrLRgv;@B&NPB5R}UIBZg;h_;^&OEn9C@1@O6f$~w?;4GL!2nEzq$ zZ%q2TM*f`L{>=}{ewK-;vWbGK3)6A62$=2uLQvfWvGN*r1s7sKY(GKm%{Uz1aTPA- zh6-wI%VGNdz0h^la2#+AM-P_+g6_71D3V===}dh=W9DIO zH)}!9+;4)$#r8;f_zT0;JO#Pf_lQv$1tjuou9Wd6?uE(O1SE<N@;XvA^e8x;!B|aWc#H4#2*-YQzOpp%S1O112zw!U|&2}?leI=$(JIv|wNzn7{fY1TCSTZA6 z&Q3wpPgVaJ7i7+CHg=o-9XI{|a{PPP%WzFx=PjTRUX+DYin{!1my zr`T5hrO?eYT9yx_JaBhv9QPWQ$-r=RH!H+phCUZNVVqB4Q_w2XC>I{XHzZMumB+x3&qL{e!V(Sx3x&V=rhd ztPssZTdPtMUvmccoT%EG8+1@hH)1yUGFQJ`gUG7}i_169k+y`s<5zh^NEbtzIqOgv z*JFqoRi72gay-)cBz-l0RsT)=f~r_iEI3LcidlB*XV6LPpq6}> zk0duXXjNR#SjX$UeJuKo)DzDxxyhZDbjeU*ndC8~h2P#ckUq#W5=(7zh`|!4svEg) zX!y%tM8j+bEw`3YEe%&%oLDAlPVuAd?3~5Qjct3@F2{+`$Mo~d&E@F(-;{vLNNPB0m*Y_W8gCf z!KCk6#EjI0!{l#*5gm^#Hm5gzbzU$zP{?u+{h)iYK`<`&L4j2(tcKqa%x^bf->iP< zVfaC?$dsXEY9QlNz7;H&Zf4%nFQ<_z{?x)yk_xuZdLzm zy4KW=V(%C-;)TfREqP7PEm_FN44cNM^zToe>)faIvJpgkq9Q;1eVx?)a;o^{z-sBR zksd!`x`Wg!xQ2$gmy6}y)9Lc-%efyflf@B>&Wa&X??|UtN_>!w70ooiCH8Y^&*cm_ zCr0ltmvS#2B?U%a)V1H0s*r9)WX0w&B+8VE?^CL|4DC5&L$VuvciEa>k-UN&?;J;8 z(2S}brt`&j%k^2V`z|TmeJ@w!HCD7pFyJb?9iUnUm3;rJt=!z~*VJh9IU%@=>5n_5VP5Ijz!9@RG zzezJpr*i}=(-DX@bA;f%S};@D#XN0q!l_JIF#0|Z0k5{et<6Q~9l<m(Sz94PeW zeG!zXj$XRo1Oug|NEj}I?$s}X@nlEF51)y4?=A_wt<;fmaxdh%UK5NiF#lS|rA$k< zPB1$=7~4kaLZ{)oVB!A~sY-LTQs)oDH^LL$hOyhl|1k7pwhz} zvP-F}xNnQEm>Tq!zhZy7N@L|@?&GF*L~ig$nsNFHiMp31b@E(IIJG|9?D2WjdbkQT zRo_6AMx~LuPpimlO`g~&Wsn=LjZ9lVju?6QNnP&G=O^w}BR{Upru*9U6jQ{ys;|K+ zoLCdiDW9G!R!sI2JGNMpgL9KeWqhVstnh?bUgj!0_E zokK*S&4eE}YL0A-OrM6$`9`{~zQ(s(97)@=x6_Lcr7|V=XzJZ}Ci6bdpD}#r?cccV zH~zo8IJbW@?EDAUWBlGnf@w`B1hlol`;CfVzS0n3gTBILrlnx^?G^&vD$)OCvtU|w z6!FK)AOz19`t+HSuTCX>pleqx%xKeB&REEg2HvlPhVB>Nn2(8)& zGt(Ynv(R0{dFg#LPNj}`8M~sq1#_6`F_9!XNt(|*Uo10RunM@I3rRuOb&(S9A-CU=^`0j#8j>?A&C!` zachpuWe)6}&4lVN;5ClfvnR!-vilxa2n@p2n9!S>n5|wlg77t;`4y#pZ0ssK1VQ(y ze{U#R9rKM{v`>^oHC|!opNu1+D|Rtyg-_8%hbzqOstBZH_6D)O^i2EnX$6-fY$aAgZ1gBGl#o((ZCrhtiMB-ZQPKzCGiKywkz#bX$f`#3N<9fEDjE%90^2{|xNE>VpmJZ$WZL2c2u_$9m5{AO~kRPW}E#l*Wp(xAHQ%luN65gYFFC zp`U{M$A}~K;7{y!V{`s)eh)A4WGkbT$ROdn1jMIKDXlA4tX4qeIBPuKcn#ced;!sA-B^#F zUoU#mUWC9J>nBp~c{PDBJqfHEcph@ZD96M+8EdP=LCz=>2=1PZH8Q`$^I>U)}GjN;TjmK5IfMj}y+Hz?V9_K{aDPnWL@yRDVj{3L6Y_Woc zI}Gr+Rn%u}WHSho!m;K-Z8%2X1t&(#!deEY5Oag>j@%rDHRbK$yiyZbONL-Asc(># z<^x9VtypU-2ieV=VE$A~tTkK-uEiO^yi4z~){uBO<8mAVzp3Jh_XFU9M=5Mow#B9v zkI8m1U;4l_si4b8l!UyR$t(@DVcv^R5dK`fh)b~BNLn^fw!LOQlUMVDb#8ej?A~w| zd9Irx7<*fXy(IIJ9dgkY%`f-hW^cZLux}GmDA>#DoLs@YyndpfYvn{VSwa!HmQF#^ zBX#+SRVrj_Lpyo$k~*AR?d5JgPvr()TtQo?H_*dA6Ean?n*^swqG!+IxJw=Dh)lZ8 zoln;VDCNy@&TYssHbk@r`G#H=Hi#`J`c{o7?fVZ_Wuy-oH+?tXn|_SDbNPbQ`lKpMIm5pL3bPl*ioB3Rx23X-XJd8R0O?X*RasDneH+Z~dcJ{%FbH z-1t}R%xGQ7GC2x+^v7a#+dFWX?nDF_+{UU|+u&@eIBfY?gSGCfLh6$nu=8dd)~Zi~ zvu|r*<^3|OIXDW=iu{IU(cM_>b^u&D6;9`mEU?y|@08W=0`s{YSa-n?NOFi6CR0PZ>zwv~PQ4k`202VpBV#Cpv5RJdX6yb0@A^$mq4J(52 zj(f3D_ag`f3}%Wh*u*>#5;b3f(M?TkP%{jYyaPe?qC6h2@dDC1M8Psa3hS9Cz`6C* z?)7aD)_HLhG9&FF@M{M)m|F}NOxqyjmMNa#iqTG)^IZSkX^c{RF1gu~&Z}HJLeCL4 z%n*~i!WW_ENuK*nl>8xp9s76@tF)v_aC1y6BRz5i3g|y;Benb_@8N!cDZjKI9m`se z${!Dqlz>IN!lfI6$oH8tv(L`Bx&Hhe7%oY~fXo+M|Kvh@RT!o#Xx znX;sL!mkDI`61gsF;;7h(7QRkMAn*mVUF64Zl^3@2GU~C0(&hKWc(5NPkf8^g}oI- z?;U}Lo<77(i}hw=Z&81bA7bvZ9w+`N{TBTf|9|(H?f&PZny(oT5oP1C!n$(E?K6Oo zhGsk>yc#ZFroMnCi?P!6B)Igh6=JSBVU-OZ;H(v`;Txl|()%Bf?lu|1j7snrx<7nw z3l9Si^o0ZcY0Nd&}ow)taktyY(y_ z*bt93w>>~Z*$$$Wki}FgGyFA4Y0{(E&Su@Iv)I}%I9xp96Vr@B^QZRux+Pj@x4P1=OEzhB+gRWd4-H8^@awjTBE-+tPKa!~M zIm98Vo*WRpNOrznM#kN{%w1@sY^d@C;vRCD{~B_D+)tfC3deXMrPtETap&m-R?p?; zPt+y8hKPh7x8bFW1Y}mjXMSk94LXxOi~II=6D$4|6^h7fB8h%AR>XJ`ntII}y`JaF zbqB}tr*2*&k)8QM_ahh3k}_{JPSl(mIJpNYzzt^Fl+A*Lax_;ORZR3cCjOtccm9cG z|E(u~W4mdzu3Q*46apvMf-BgaM)u!vb>1)PkD%PUWP}+ z(^*>oQ*a>C9V=NgTm1pVT(N@SmCLZ+Ho6D&k}{n`FJiUt z($u5jG5C$(u-dT<$j-Ec;MS*j4EY4t2Erg@?ovEXg<>=PQJ}$pdl8bDg!Y(VTMJt>QQTf6y&NRJOcqbr} zghfZO%UU;(iO&Z45!jTZizRZul&iV%>M_Xa=o>U?<~!maw2oI8oXYPME8?3Mcygc9 z_n-;Ax@e#GVqPYsgWICFj>}xq$~BbiMdsO}s6jhY5Hfk5V9d-$_EY?7Zds-w^48u* zBuf0LA7ZCqSNB+S&2Sm*r=*7&b^WieLbY??PdxT-Zv3luRB&s8YnQ3QNMys$d;^N#d31}}#ItX%&T z622&d)6Lg-+_d8mIr0z$ssq;A`vZc1PJ{z$kMOvxLD+Nu92~H;!>aUcU@QHqgl9~^ zI{OO1Gt(WS$Lz-1(%rC=p9Ep;C3u2G75K{Ugs8*Kvi@nd@Qa#y~voqC8~Y z$p`PJx_I18X@o2;pw~N=3o@q;jX4wrT^JfK+^g12h*3ytmT+_pjPI|@W1q^3z44j~T&WFju?bEop^et%k z)OfP$^fRt_@mY3N(`f#J&n0p`X%Gbq-I473T<-bsXRO4R-|QNCrpX?-!OFyyl9YiW zMs3eZl6H3)_uF(5nSraA8wG0QeV-ROHM)sAcjmg_b*nT<_BG;twXd@7hfC2I+h;_g zHi*ku=a2eJd|36BubD8zN&E?qlbr8@=LLgi;Y@64l69HgdO`A+c(i|CHqDK&yfK56 zm;Il{{n4C%bL4MqXHDzMapffN^n8OypQ)kjrJ=CAWgH%@_!g25#ev`1B&;%iH6+q= zL~zM0tn6Jv_v7=xv+5F7iz|l+U0Lwh(1ewT-lKo_M_^fh1=et){)2ojY_s}`HA8vW z=Rc%dt`7|1~@3)1}wDWlU z^mpKWI1nP`I_W+60Bo2M4`Ics*wpDZ986D#y;z7R^lgIBT?r6m>V{25?u5vRbdM>+ z59=#XCc|QP@NpPU&nWagYujkpoHhijKcc>zal61}X(raxzKEPR?;!GD#K`A2%KR~= zAH{1tVin%+XZ+T#XYP3Fqwt#hsMO{cnqe)2dQ)d`j`w3YOW(>1g_SY*OA1VXKoU_kA~>u;dWLrW}G$jc`2SaWX{I&VJRTQl*3lR#$~%QhlY#jmk_U zBfg*6GLPlDQuD}&w)3p!#!Ia7(PR7}{VKr;&B8O*vuEwMmUH3fuai@2 zQ-sO3$%rWa;x3D>VP2=T^TD|BBS3)M2#0QeF3>RMY*B z(sRpyG5nh&e`7lvT30d*SAzGGUaT~B8Jr!y1Dt1$!YY$LP_J$`2!tY91C~PkDF^VM z8Hts&zCxnRdGI$*z?u+1cMx5{<((qdJQ4?KQnZ%bkHXr?%@Dn#4tB-Q#yUz#5Hghd z5UROiP1nN^;*B7beT>y6>p}qacMiGEVC_wn;Q8!3gmYW4rj#*k&ZTw8`ZzXtmIhAu zZE3I94NtVnh6Qh&;NbEX*x)PeANm`>t^$8-C|ylwf|DUIP6V4yJP476U9eM=_Vlvm zz~R*8;J-8&8ya~)^0Rcxvzv#NU!8y>HoG7?Whfq#R!+2UIdFx^cZ8op>-j}bqe&#! zhy;NwY95=yNG{{ZJ*`}#|4^5?xU>L$Gfic_OkTwOh&fAw^ga`db_LGl)oa#j;S&&d#Pi^z13y)d*?hZI=sVR}>^2@h9m(;e1IRxkBDQ=%~(DJM2F!RC9& zp6PwoSq%;B^qUPR_eKqqld;O$xJe$JZ)e0`ABk{A~Bn~8hJ@ca0icWB+q|sK(WgXFnq=iE=y63 z*qT|P{k0EK#N!vlc}^<5Bl~y_AK&&zZ~W0Ge{ylB_rt^ti{9eDA74^O6(9U zZg$3_^&BAelo4z*zkn5TE2%HT1$w5*#tPa;A&pIf9rNE~<;R=hI&tdOlXk?xk-)yI_CfQ>=Eq1|nS(V8^vZSbgC%h$x*2UU@cHwO$PNe;o$ky@Sr6-^IYG>|(-5B~ zi?t+!sDD}`q{Osf?bF4OXtM^Q`WIl06xy#_xgTQtyRpX2iI85#LdeccJi?yd=OgHQ z>GH*Rq+$}c`-u!X6CBJ4LhP9X$u20OJ4P@kBnV+rjz<0vK}J%$Q5?_krVf`-yZdSq znmG>nzMMj2t~sE2J@c*2X9I7$dl5Idp_IEw+2)^W4IEi`_&2^=HKy&n-vZz9e zEY079)`jY@`yc7?vB46B>JQ4$jQ29kwQ$XXn^PmWr(`mdX=A}O_S_&#@)Nm&kI^Xc zr8)_d^GDa6efewSHxR7|1!4BQ2IiWYIGHiw7V=yhgjNshu(1;<xZ?2E9Y$pa5tA__NXuXaD3b&}a%02f{8odR}a`K)rtIM)W-7j4FJhb1BF z-8KkXrjHeOPJ}F4=e_z8u;OSA@*38|o-_|UrgI6Lq4Sl&@93;r!eU5%y95H~j;8nR z7)Y|Pf(;Agv65II#J{-#yDLSo#_d;>^|BrOO73AzaUmQVo($pFFJP@2>XoRo4x-9d z)ANTcWp=ki_{Jn`Fv%NE{-EE^1~aT#rUMz~m#G*01+1M^2+Sbe$y7{>{5wdd)17Fmn|$&wN12#e>Nu>uKz=Vo_37EX`ZpMCcqlgTKDs zfEx_eMtQ^4n0>Nu$-1?1XuP~A$$Yk1SV5V$l}W3)RmQcv^ubti^w~)g-D<)lw9nxx z+dIf}5lJ+C=4PZl?v&uhl;hTyd3Kg=Ad9yL&&~~#`OmV0XU_)EsF>e^RR42a-m1@n z@5xtDqFVwP=T3K2`$gy3I3E0?bk^y=*yC?*{Hu2Mw60_&h*DOGv7NUUQJSynGa9nGte?8xtI!iMXp#c(;&bnhegXSDLCk~Xn0Y+<3uTXjMB z7@qk#y^NPz<%%+Q11qz7A%Ad}1V1Hv5<0S9hOf+*L%XfI1&L0%OyizvZiKxp-N|{t zOjAWZq2g zV?H0)O(I6EvHK_b>l z%!Nz`H_C1qfi-sif>TAafZ5lL^`$n!DH|ae*}Gx=x&Clsc?--|l))3SC?B_C1R!T+ z+PD1y@z!QA`EfTkoV*iGm>s1#)Pg7YJ%&U&>*T%E1{=0fzh)gt@R6YXy*++#N?ICr zYbRhmd>m2*55Q-~46JCr4U+CwK#;069-A{LyiqB~RScWJeKp$0AG;(;&X-N%?SGeW z>*wAkht4mTj8q(fF4-3#Rx1EKka&m%AzCKXY({U8I9G9aJnd0 ze$foAkyk`vtAm9fi+&4A5;O$QCII@rXA8gG@F15mrrWhV8z7+~=8^C>f99GM%(hU ztyT}N$K}Dwj2l>MdOKWu^%L-F6|B_|0XGjk0E-EYSfhSEJ)qD zkJI_?}It>F#8B{opy^kgj@7}vFho4tY9#U&Pz`P zZ*fzsD!(824c6d$ITfpAIzpbWA_Sg#g4M>$K|Z}tFa6w$)e9fMt?ferx0KQTsV4AK zn!t81y^nm7hHFiy!4!?f8hJSNJlweE0hXri!tga=w6$PYqTxrChsL@|5#lfYn46!?|%$uu5Sc z9w%)Ld53zyiCv48182jvBscIqDZnc3XW`Z^SMcA=7(r8{aHY$`5Yc(6b}Q8w3T*XH7#Xw`$S+ z#9!>=j~2X?!ddo7GDG&;t}Gw}E1CIsyvcV5mOTIT5~<48aZ1N6$V0oMNa9)ztFN_+ zpR3`{Uaq%C?pI!LKE+|E!sx=M@sGr&FxpdZFO9d`Xu!lwFJMi%2F_7VT8|G}gjpb|)K-!=V zAlKb^7-e#t*f1OxHC5qJQ4indssq32`;M|!5%YJET+E`g|59W+@EX4Wkq(N{2!5gyx3d*#En_(=olB| z@-2>pY{_F4GBK-`QOFNXY(tq(W-;rh&Sw;3E0FwmH8Lilkc~Ev5$yh<$Cu6sVr}!{ ziSt_#^1@RRb@q6XCc7t`l;=t$NNDCoH<&R&M2fj&nZq68mXQrhL723$6*<&B%zm4cZ^$!uhLyBe(K)p~tJr(Dtk&?BjbGjF|KZL6nyfS`(Ge`G0UGp$g?B zasCL}d-JgF%a;8=&7ynF|BJJ}{F@_xW4qQNaR@(t{(`I4G;$+BNw-+|0sbI<1D^2rBXHW# z&mBDeg|+ZDVpqhwq7S(qs9?!!-Z4?1JY2AYIdtg>!V(EYvnwB+d3c6b5k?5~FYf0p z3(bXf*S%3}j)Y+AQ3o>Q>>5G5-zhS3&M7{$NS-{#Q<$7Jz2sPsqo5icK>MB<5RpyY z+zo9HG;w_hYqrr4m3n7#nX3cPy65|tMd~Zinxd-dW`3)Ao8ow(dAte9bBf_QpWWeh zmF!|O0x28wsth7Ojv}XZDI`mD6ACoHg7(W#MpNS*=uT?r@u20DRr;UOJM(|)@;5jB zRlAk6u6$5j43lOkLZ|#G_{0jq#PbLInA{0(P8b9DJ%Jw8Pw;#p1E^vxW%fluneHgC zd0dG_u^qhdD+jYl92Tvygeuh>V2}Aw9>)-Px>gw$){VsC3#UVo8ud^-JqHgNvI4lr zk0|d?5{paBggedeVeMOOEIG0h@)nK)H|;hoQBS$p-nOvSZa0>Cp$G-$p>Uut2oL?d z7V^uZAo$m0EVKFyJUPz6*7EyUD%%W7FIPiw%M&c!rVlSyse}8mMOeb_3%vcf9y}`F z(VdlOsOqd3;0#-JNlf-LXTG-%EF~Na+oJcyBf{#YB;Rz1ot#uiR&qFIw^X&l32p6=CR} zC*nje5#r`Jk}K>7#zISr%QCJ+t4}wx>33uK(X|H)#uvDw9|cE{cDfF-IQ<0mZ~e@! z%_8i&H$pa!i$(mU$F_DQ#&llXxav@3!9Z-SjRQ^!PS*G`)A-Q<|KEKE@f;-n% zL0smEFnU{oB@(fp;SO7zY`qbJlla;V~JhYwtm7 zFNDbd@((&Q88msWmCXOChn6f1Epk;bX~S7)4;l?M zPB~z^{wp-Qyn~AO@xX?xgl4BesQdW_7QQcr?i)5xQ%Lu2l9FJc$OOJQ(;bntcIbX! z2JgZ@fron{^eAkFmwM~L{ookr%W#Ef^qp|&2SXS*_zNC?doO$%ZKM_TlSaCg;8RVGpFQ)X=5AuBaK1Tax zoG?4dk4U*~B3cV4p>Vfxq`Ln*^ZTb7xloryT%V>h@%|@}#=$e_fZby*{81rNx;-8l zL`!njw%>&3791su=82-zH$N!{MwF}@?karzQG@QJPTC4T7ynW9KWhCqH~v*SXIfX@ zy3U5Njr4CcZV;*>GC*Zu1(w~t1`PN8Ot_!lCcKnIa9ud-zX^ZP6UVQ6fD|R3|vMyOuwvz z#U8W+_v0t5m>~rNb6eo1$!S=+tP6T4+=hD}62K?P27cBRLg8Ug*tJ6%x@0@ywzU}D zMVN*+^(Q<^!Bn?>G{t-(W=fX$2 z?>>2z2NoS=1a)=xFri8h`n)`ty^zdxf1AsFemjY~sj`4KjJ+Z#(L9J&^gUzRiwN0~ z7A(kaJ;j@xHAPB2*Ga^Wr6hW}p7kA+Cak)(kWUSKMb4i;&3(Kl!?d4SPHuW`;LK`{ zF~y&!Bk}3mk#GGp=6O~-C-b?I?N@K)$3?$mqgD+=r^~#^@%EKOfBjaXxONTtI(;Hq zXj)J19I~X`vF(hg#93=kuUszT(RwoM%T%VZ<{nycxSV|ds!J5z%2C@|Tl9QR6{|WV zo5}OaMdp*$gb694=!jdkP&3Vfd^^*{E@{tX(eszwUFv;fKJy*7@7fr~dvK7L4F;lJ zh4js^QQ^kZz@|S+dvgE9&;HGkzp>p~T34E?3t+5hDhvkBgzpJeAeU7JeNk!f`Pc(6 zOxA=Swfmr2(i05*c0sS@GHA5@0@eqE>F<;c4d?7&%7#ijV=gk!`k(mmuYJO;Xa~Id5 zxf*TR!m}bmB~&Y$#uV1pk~tZ5=<*W{2Q*V`O1D+C5ByEp3b^hcb?^ z>!lVl*>19=Qt1G5%yKqsn&!jGj=sizm#tummzy%dTB8_8w2aIaX%~js-QljaalG!W z{pg_V7JmNTQ^-j54T+BR74{B~;U%f-;uqp0OxJB*zrf`d}x!UF;z5pKuo1nH@+NRNlvI1kLK-H-2HoX-?;S)B1hKrm{r+YB8R^Ne| zr^z-SgWo}yRxh;TUYl0>f4&!tflmzWg^YHC_RXK5vfLcT9%zRS>ecbG)B}bKheEsd ze5eRI3C5ID*mXP-UQpi_bDi1H70$p%gA@?V*#uq9M(}>$GFVVO9C~th!s`z%un1G; zn_)3D9W{a}oubg8;sD>*GyyeGg|^;K_~tf=?imT8Jy9My$Ls+m=Wv?;lx->Y8St27svgy z3=!`7)J)cxWUilZ8o14@$h|m9u_J2ZBwtj0J{7T{Cd`4)99ZKU-B_@ z#Q{k4T!;1vy3q6X3yjDvho4Un^p`A$p^v{}k-aU@vG+IVQf|kf!Y$}tehN&g>5lP@ zi_laX3`Q{n&@&hUpZ9+Nn*lTUF*X*y$!`YxM-yP6VIq8%UJP0@K0*uSd)MfT!uZKD z&=~0i-xi31+_nz*`ip_4rKupB6&Z}CVq&wColD3I5%VCU39Zln^RwK8*PfRAs5cgwQ^|>;M6WnWkn)h z3KnHCAahWtx{{qqY<)PgH#pD3mi{IPShjI9Ww-~ za?K>7aU#2*+m$y^pDC=JSHVq_trIxiH$&EwhjYK@cas>hmfVwRLI-zzVzS?RviEyZ z*n5X z7rK)6;QH*}gbtx|EC1=v@D8 zjLD`f;S70bt?dE57pCyj89{BbKB$k5g|@;iP%qXE+VBe+i{s$EAp-gS70_B{5ATPc z0Moq{(BoAIWo`&2T4lnZnI4or@CD^Z@i2I520WMf0M>B{Sk!z3JldTAmcqqYymk*O1F84I%*erVK6)V)TE4-I_9-JMuOG``>Cf@N>A zAsUtZxn=jsC<$$JvCfU$E^y?Pa^5g8X;aC%oFK++wH8r|@8rBKwxRgde!>%dm&sZ- zl20n$%Jk)*MW;GliCe`+!Y^FIFN$g7!-kd$Qj_{nwHUG(6YC`y7<-?1etpEP8NY|M z`WQ=&eYwKqK6XM8&Gv%dw_-`@?H6dq%c)Ft!z<$bQl9y=Vkbu;LXml#JUTt@8%kQ5 z%F2gcMS<4-!t)Q3xQqvTk(TaF0aqtP!7I~kY(EbVKlOpm$Ni^KfAsXfIr2BQ+ZZf@ z#csNSd_pVq{qMK(%>?m1Bj8u#efViQ5)_Q4Ku^(B=-xjL#_ZOC!RAQlQ&ffVD^5XM z>4GUYKSEcF91Q3+f!@LjXe_gWmRJI&mu5qo4uQ{Gu7dtzQD}@^0!{N;K$*zF zC+Df~uF(mMmdL;ttGiJCWj1AD(Cgg%YGp|*;xy? z`Z9dpoDJ1EwqRRl2|dClc&Fn6j&#p;V2T_xZK6Bz_g_Nq1Ax}8*Mf051SI(PUc(6){VKF*ZLbs+Z{8s>Om% zZMvX%^eqXQvIxyM-#}uU-m}&gN6?s|lIXC=W$vcKTgLiwC!_COM@n8~kO7xwc8F88 zAiTeYViR?aK(Vb~jf)|)X%&3O%pb!j7NNw4{3J%m5@ zvjE|v14yrW5;u3_HZGCBBUrrC1qm025V56mQAzMmCee8`xji~e*!JCrA)B5F3?uK* zS?t@@nwk}VlzPMb7vK4t8~>`EpNI$^^7$(`9gT-($yIoWcs95@|AGc18G3eE2o5o6 z&^l%z7Tx*;W}Mj#JxBYYr}jKJ4wS+-tNYNUY7WjTU%>Z;Z=ff;43=oiK;7N3&`Nu# z$XFR#bX?(!{sOS_2!;C9vG8TF4&XBj-~(l4*UbG6<9Ez~hC^2HZdVBCygmli{AZ|9 zcLCLp4$wL<2i_LdgG?M{VsG|^@=c;3r7jPR1vcnC2EXqt zhL);Z^lm%@dZM>LXNNjW?azP#&vRJZVGyQT)Ig*1RxII587&icLyN^860qbAiJd)@ zy#6?r&rG_-TQl3q+m!9hprk!nXk5uf|2V;q$lJ(!@1kr!35|mA!#QM4<{aX5UO5FY`UuMb~2b6avf{o2t$(!FB&aASCK$abz$aPaBG0vUBCfz;9-@CDq zm$U9-T3-)AkDa=>ZQOP;5*!~r?pInG#508eqA{Nj%%>&EsxC_(iJV}%8Z!G031519dgtncB z@letNOGYO{@BLydnN$OwnpN<;SVi3_yqda_Fab+1V};^xQcJ{q;gv+$9e6 z`k3g}gffk1(`1;~L*xWh{jq&sxZ8Hug?}~(;!>i!S%DXWB)e7jln*_DB8DM@~ z1o|4L!cU)2FnU`C0}~CQPfs6o)(v3MGqsfcT>)19+VJxk?E%k|0Snd_i^yNYGLw5@ zUOl~6O5tL*xR^GUi=F*jwKt>C0o7irmk zg(%LlCwfOl@n3hU2yQO0V`8?~32%kh^G7{+KHhFG%eG4JhT=BNz1|D#1GP{hc$|vr z`aUq@_V}TIwPEDOxUdK-zI7gnWHAkCPTQGOFClR&2i^#}ToMexfN5=m0 z;YMVn)8G0S(~&!dY?n1)NbVTQpS#0c?RtQkD-uX)iXNJKQHYKtJR?`A&&-@63nD50 ziPw<0!|B{?CC@|WaEEmQSV2Ys`$Sxy41QROR$SSHw&sSDqY5vO!t)YxsH%+7UPr$< z-^BLnFQKgU|CF9_|5Jy*x$&>sZKHKX_Noaioa+abTSBpn3FXqBJ_n`!C-Km$2pI9J z@cwZH9u|=TQ(`2b_M;&lLhll``gQQ>NC1{NKMCyd9{8628H*)s1jie$@Nvi;Eb{gw zn2t4p&sEc)&t3~ANTkEZY7E`ahlBa^La0)df-b%kMyq{;n%z@r&$t)lHN@flH2T|z z><5XgCGh3cTj)-3wy7;y3XNg{dN-bCQwQbnY0nTW^6n$Zo{)vsl3!RXh}iu8@*BDw zO0ih~SkN>%0j&X_v7|~e=+Bu3oky=?Y4z=3yyG2|Ra9cB(Ia6>_A4m)I*gSyvtSC@ zE5yBAgg+WNg&lTpAA0v9MlekDD|h~MAY(s5k!$%VLu9LWpiw~|h)0(n^D#h=nOtCm z_E|pWjWrU`^i%8DA-dlgUl(zH+M8IRZC4a??7}qbZ_d?Ra>Zy;F1HPh-mw}Tx}L@S z-ntjP_Y6aR+pM{pvF&7dlO4&N*@V)z&Sj-)e=x=OCUdc&+T4xfubGglZc_B|9h&9- zLGWu)BwwM@j}#M=(Wq;yQ2fTR-1)70dHEzuqFOwfdtYD2faps8`}l` z@4Qk%z2at#hcER?Smb33-DNk0=Fsz4OiBo@Pt2g{vU)O!|Er-f!-~B4U*= zEjhc1hvnZ&}%Xcx;EVhOJWVJ8pEOEffLwKubM9A z0G9lc3yX}L;B(m|EG?V^OGO=_S~-O43bG*zY{%@G-e#Ht|yhXX6(0RrmW1s zX>#<*5~OvbkCl(z%J^=mVS4iBGeUhGQv75Jx?>rPdh@k-wKsPPOtpS9<`b?Fos@bu zR(CBOblHb|-?a)~7mOtvl+>A|<*8h`O@uJH?j0GuYd&+_I1)LPEJTLO;+VdHC=!2V zEUJ;Ab!G5-qNcL#AC>&0ntyZSU$qPRUtJlh1m0tF;j@lCmg~<4pH@Stzg&)o=4rx` zq5$|>;)SIrkAmg9i=gAfFf1{8Da^Ym1@$tcv6$i^SY^E#8l+BRi8eytna{zykajG_ z{s5~i4!*p)hs6gXL2qIn)Q@n*QsP5FTY-V33hkUD(#O%BIzZ1*YTa*e#e7cIoi%*A7>`1tW_wX*v&nX zFkqehuIrl=?Fg6{<{TfE(qQaPlZC9DnCneNlSKjQd2Hhq5Pc{E2^KXv)jqP^R zx*`{}7v|Z7LSgS^ESE<;k#86QxloN|PP@Xa`R}3lTPc?I6#;9m819dw^Fk*wfU)}x zujnk~h~%pi&NL{hBZ%X`axM~3QEo*P1eAiHpexKgdlZQ%QIQhGL?f1fSrQ}( zCPLzY2IWx662K)&kV6wrB@h&L=Mgoa$WdGpPDK#bVgUga712ym_{C5Edhg?_eqA%& zzy9|qES5FEU|KQJQcVUs7hiZPN+*H{8!&#U0|PFnh{~mG(2bD7kXS(k1_}_wgurOe zexlYC0(14Mpp$vUy*+jvgcXU<*49ik=lth?$w7;r3(<%!0?RlvsELjznjN{YqtylO zHue)O#`W)I?0@t3p={2)7>(Dv;#)YCZWRtA-{y0O?-k=KsUCFI%0X-_6`=cP*pAd# zDL=bXgqP-};Hc&yB->y~_xJkYV}s{;(woW6@>b&w4+^=Mq)~jKqzcETgwZWc#WdJ` z6-6eOaPF#d-W>hF{PMGC#^i1^a?nA}-(Nv<0A#h2NWk5{sx!B{H$C=#caN@&8@XKBBOHO{tYY*w5ORk7Eig$ZRi zd(8m157p9Ir*702`a#lpRlCb=$$n;GWH_XZW9P>YCQ) z?_%S9U3-M(m6=%^!P=jFyQV>6sGkEL>MNi%sfEn&&wvGSH=%tgCBny{FmtXH+Bs{Y zS8y2?m*&BvbjB2+J}@0pf+B4v(N9)_YhMElq(&0$WFxReWuWvlWWL8N$BcKtxE>}# zO;zyhXn}F&{UuO+&fZJlrQ2WZEbI*HcI&`f^&oh2q!Mgj7qA|X5GEMcvWU%ps02x1 zY}OVqcLkUV9V03l0x;TR45L}@@XE^^gs1J{$qO~2-c=8Ct6qarpVeW~N3{LL%3$M7QjE6VrNYema+cA1F;RTJ-t>E)gE_0rH zY%u95$D7&m81btqnrT}ow^UAIiyhjuI=>1%%LqWJPY>emvc0_8Av5>F`IH6?ttbz* zV)y#d2YCL3n9h($*vwI-?=eXz8`0eZzPY_G^LARi~VU(f!B`6i6j4TP>`u{5sJm|p5M$MFFf{PoEi zn(1fke%AH|_GZjS-U?@Q<%3;ZaHA?e5Yf+nb|ai}DNgbZxd|>x+r@7aWuaZ-B+fEN zDl-j<;@8#nxDTzdqvz9VWhHiB&`CFSEaHce+tdKPClAM}X;PHK$I(-vbu?s|8>()x z#K$Kz`Nf9Kw0@sIRvt0HKbvs~KlG>7%agJGgBo5g8u6GD&pT|2r;bk^ z@`kt9qpMqQp}^FQ_*(F9xboRoY|n2x%~n>?1+9DdUot~Ei$fNa%MZirHw92|7E Date: Tue, 24 Aug 2021 11:23:16 -0400 Subject: [PATCH 62/79] Enable the grid rotate test --- test/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Makefile b/test/Makefile index be29d1adbf..90ede330a2 100644 --- a/test/Makefile +++ b/test/Makefile @@ -156,6 +156,7 @@ test.atomicfluct: test.grid: @-cd Test_Grid && ./RunTest.sh $(OPT) + @-cd Test_Grid_Rotate_Simple && ./RunTest.sh $(OPT) test.unwrap: @-cd Test_Unwrap && ./RunTest.sh $(OPT) From 4654e94690ec368e3e1370a59754f1002fdcc5ce Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 24 Aug 2021 11:29:56 -0400 Subject: [PATCH 63/79] Update help for grid --- doc/cpptraj.lyx | 67 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/doc/cpptraj.lyx b/doc/cpptraj.lyx index c69b9eae62..84c1cd6b1b 100644 --- a/doc/cpptraj.lyx +++ b/doc/cpptraj.lyx @@ -22983,19 +22983,39 @@ dipole \end_layout \begin_layout LyX-Code -dipole {data | +dipole \end_layout \begin_layout LyX-Code - [gridcenter ]} + { data | boxref | \end_layout \begin_layout LyX-Code - [box|origin|center ] [negative] [name ] + \end_layout \begin_layout LyX-Code - {origin | box} [max ] + [ { gridcenter | +\end_layout + +\begin_layout LyX-Code + boxcenter | +\end_layout + +\begin_layout LyX-Code + maskcenter | +\end_layout + +\begin_layout LyX-Code + rmsfit } ] +\end_layout + +\begin_layout LyX-Code + [box|origin|center ] [negative] [name ] +\end_layout + +\begin_layout LyX-Code + {origin | box} [max ] \end_layout \begin_layout Standard @@ -26230,7 +26250,23 @@ grid \end_layout \begin_layout LyX-Code - [gridcenter ] } + +\end_layout + +\begin_layout LyX-Code + [ { gridcenter | +\end_layout + +\begin_layout LyX-Code + boxcenter | +\end_layout + +\begin_layout LyX-Code + maskcenter | +\end_layout + +\begin_layout LyX-Code + rmsfit } ] \end_layout \begin_layout LyX-Code @@ -26362,6 +26398,27 @@ name/tag> ] Location of grid center, default is origin (0.0, 0.0, 0.0). \end_layout +\begin_layout Description +[boxcenter] Center grid on box center. +\end_layout + +\begin_layout Description +[maskcenter +\begin_inset space ~ +\end_inset + +] Center the grid on the atoms selected by . +\end_layout + +\begin_layout Description +[rmsfit +\begin_inset space ~ +\end_inset + +] Perform a best-fit rotation of the grid using the coordinates selected + by . +\end_layout + \begin_layout Standard Options for offset during grid binning (must center grid at origin): \end_layout From dd6169403f297ef5add916082fdbb396559d43a7 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 24 Aug 2021 13:23:04 -0400 Subject: [PATCH 64/79] Add some examples for grid rmsfit and maskcenter --- doc/cpptraj.lyx | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/doc/cpptraj.lyx b/doc/cpptraj.lyx index 84c1cd6b1b..837e709631 100644 --- a/doc/cpptraj.lyx +++ b/doc/cpptraj.lyx @@ -26626,7 +26626,9 @@ Examples \end_layout \begin_layout Standard -Grid water density around a solute. +Example 1: Grid water density around a solute. + The solute is imaged to the origin and rms fit to the first frame. + The grid will be centered on the origin as well. \end_layout \begin_layout LyX-Code @@ -26654,7 +26656,42 @@ grid out.dx 20 0.5 20 0.5 20 0.5 :WAT@O \end_layout \begin_layout Standard -Generate grid from bounds command. +Example 2: Grid water density around a solute. + The grid is centered on the solute. +\end_layout + +\begin_layout LyX-Code +trajin tz2.truncoct.nc +\end_layout + +\begin_layout LyX-Code +autoimage +\end_layout + +\begin_layout LyX-Code +grid out.dx 20 0.5 20 0.5 20 0.5 :WAT@O maskcenter :1-13 +\end_layout + +\begin_layout Standard +Example 3: Grid water density around a solute. + The grid is centered on the solute and rms-fit. + The density obtained should be equivalent to the first example. +\end_layout + +\begin_layout LyX-Code +trajin tz2.truncoct.nc +\end_layout + +\begin_layout LyX-Code +image :WAT +\end_layout + +\begin_layout LyX-Code +grid out.dx 20 0.5 20 0.5 20 0.5 :WAT@O rmsfit :1-13 +\end_layout + +\begin_layout Standard +Example 4: Generate grid from bounds command. \end_layout \begin_layout LyX-Code @@ -26698,7 +26735,7 @@ crdaction MyCoords grid bounds.xplor data MyGrid :WAT@O \end_layout \begin_layout Standard -Create non-orthogonal grid: +Example 5: Create non-orthogonal grid based on the box. \end_layout \begin_layout LyX-Code From 919072ead20f819fecdde18f588bc9a11e7ce466 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 24 Aug 2021 15:14:13 -0400 Subject: [PATCH 65/79] Disable progress bar for easier debug --- test/Test_Grid_Rotate_Simple/RunTest.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Test_Grid_Rotate_Simple/RunTest.sh b/test/Test_Grid_Rotate_Simple/RunTest.sh index 5ec46784bb..30ef34b85e 100755 --- a/test/Test_Grid_Rotate_Simple/RunTest.sh +++ b/test/Test_Grid_Rotate_Simple/RunTest.sh @@ -9,6 +9,7 @@ RunTyr() { INPUT='-i grid.in' cat > grid.in < Date: Tue, 24 Aug 2021 15:15:35 -0400 Subject: [PATCH 66/79] Start fixing gridaction rotation with multiple procs --- src/GridAction.cpp | 17 +++++++++++++++++ src/GridAction.h | 32 +++++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/GridAction.cpp b/src/GridAction.cpp index c44b5755ac..c89c40a99d 100644 --- a/src/GridAction.cpp +++ b/src/GridAction.cpp @@ -157,6 +157,7 @@ int GridAction::ParallelGridInit(Parallel::Comm const& commIn, DataSet_GridFlt* // zero it out on all non-master threads to avoid overcounting. std::fill( Grid->begin(), Grid->end(), 0.0 ); } + trajComm_ = commIn; return 0; } #endif @@ -216,8 +217,24 @@ int GridAction::GridSetup(Topology const& currentParm, CoordinateInfo const& cIn return 0; } +/** Set the coordinates of the first frame. Set original grid unit cell vectors. */ +int GridAction::SetTgt(Frame const& frameIn, Matrix_3x3 const& gridUcell) +{ + tgt_.SetFrame( frameIn, centerMask_ ); + tgtUcell_ = gridUcell; +# ifdef MPI + // Ensure all threads are using the same reference. Just broadcast the coords. + trajComm_.MasterBcast( tgt_.xAddress(), tgt_.size(), MPI_DOUBLE ); + // Ensure all threads have the same unit cell vecs + trajComm_.MasterBcast( tgtUcell_.Dptr(), 9, MPI_DOUBLE ); + rprintf("DEBUG: Ucell0: %f %f %f %f %f %f %f %f %f\n", tgtUcell_[0], tgtUcell_[1], tgtUcell_[2], tgtUcell_[3], tgtUcell_[4], tgtUcell_[5], tgtUcell_[6], tgtUcell_[7], tgtUcell_[8]); +# endif + return 0; +} + /** Any final actions to grid. */ void GridAction::FinishGrid(DataSet_GridFlt& grid) const { + rprintf("DEBUG: Final Grid origin: %f %f %f\n", grid.Bin().GridOrigin()[0], grid.Bin().GridOrigin()[1], grid.Bin().GridOrigin()[2]); if (x_align_) { if (!grid.Bin().IsXalignedGrid()) { mprintf("\tEnsuring grid '%s' is X-aligned.\n", grid.legend()); diff --git a/src/GridAction.h b/src/GridAction.h index 4974885528..24d3d43b57 100644 --- a/src/GridAction.h +++ b/src/GridAction.h @@ -42,6 +42,9 @@ class GridAction { /// \return Amount voxels should be incremented by float Increment() const { return increment_; } private: + /// Set first frame selected coords (tgt_) and original grid unit cell vectors (tgtUcell_). + int SetTgt(Frame const&, Matrix_3x3 const&); + OffsetType gridOffsetType_; MoveType gridMoveType_; AtomMask centerMask_; @@ -50,7 +53,10 @@ class GridAction { Matrix_3x3 tgtUcell_; ///< For MoveType RMS_FIT, original grid unit cell vectors Frame ref_; ///< For MoveType RMS_FIT, current frames selected coordinates bool firstFrame_; ///< For MoveType RMS_FIT, true if this is the first frame (no fit needed) - bool x_align_; ///< For MoveType RMS_FIT, if true ensure grid is X-aligned in FinishGrid(); + bool x_align_; ///< For MoveType RMS_FIT, if true ensure grid is X-aligned in FinishGrid(). +# ifdef MPI + Parallel::Comm trajComm_; +# endif }; // ----- INLINE FUNCTIONS ------------------------------------------------------ void GridAction::GridFrame(Frame const& currentFrame, AtomMask const& mask, @@ -80,11 +86,30 @@ void GridAction::MoveGrid(Frame const& currentFrame, DataSet_GridFlt& grid) grid.SetGridCenter( currentFrame.VGeometricCenter( centerMask_ ) ); else if (gridMoveType_ == RMS_FIT) { grid.SetGridCenter( currentFrame.VGeometricCenter( centerMask_ ) ); +# ifdef MPI + bool doRotate = true; + if (firstFrame_) { + SetTgt(currentFrame, grid.Bin().Ucell()); + if (trajComm_.Rank() == 0) + doRotate = false; + firstFrame_ = false; + } + if (doRotate) { + ref_.SetFrame( currentFrame, centerMask_ ); + grid.Assign_Grid_UnitCell( tgtUcell_ ); + Frame tmpTgt( tgt_ ); + Matrix_3x3 Rot; + Vec3 T1, T2; + tmpTgt.RMSD( ref_, Rot, T1, T2, false ); + grid.Rotate_3D_Grid( Rot ); + } +# else if (firstFrame_) { - tgt_.SetFrame( currentFrame, centerMask_ ); - tgtUcell_ = grid.Bin().Ucell(); + SetTgt(currentFrame, grid.Bin().Ucell()); + //grid.SetGridCenter( tgt_.VGeometricCenter( 0, tgt_.Natom() ) ); firstFrame_ = false; } else { + //grid.SetGridCenter( currentFrame.VGeometricCenter( centerMask_ ) ); // Want to rotate to coordinates in current frame. Make them the ref. ref_.SetFrame( currentFrame, centerMask_ ); // Reset to original grid. @@ -98,6 +123,7 @@ void GridAction::MoveGrid(Frame const& currentFrame, DataSet_GridFlt& grid) grid.Rotate_3D_Grid( Rot ); //tgt_.SetFrame( currentFrame, centerMask_ ); } +# endif } } #endif From f520adf14cb5d9cde4adef40ad7f1ffbdc094576 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 25 Aug 2021 10:16:28 -0400 Subject: [PATCH 67/79] Fix code comments --- src/GridAction.h | 5 +++++ src/GridBin.cpp | 9 ++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/GridAction.h b/src/GridAction.h index 24d3d43b57..bef156960d 100644 --- a/src/GridAction.h +++ b/src/GridAction.h @@ -87,6 +87,7 @@ void GridAction::MoveGrid(Frame const& currentFrame, DataSet_GridFlt& grid) else if (gridMoveType_ == RMS_FIT) { grid.SetGridCenter( currentFrame.VGeometricCenter( centerMask_ ) ); # ifdef MPI + // Ranks > 0 still need to do the rotation on the first frame. bool doRotate = true; if (firstFrame_) { SetTgt(currentFrame, grid.Bin().Ucell()); @@ -95,9 +96,13 @@ void GridAction::MoveGrid(Frame const& currentFrame, DataSet_GridFlt& grid) firstFrame_ = false; } if (doRotate) { + // Want to rotate to coordinates in current frame. Make them the ref. ref_.SetFrame( currentFrame, centerMask_ ); + // Reset to original grid. grid.Assign_Grid_UnitCell( tgtUcell_ ); + // Do not want to modify original coords. Make a copy. Frame tmpTgt( tgt_ ); + // Rot will contain rotation from original grid to current frame. Matrix_3x3 Rot; Vec3 T1, T2; tmpTgt.RMSD( ref_, Rot, T1, T2, false ); diff --git a/src/GridBin.cpp b/src/GridBin.cpp index d006fd1d75..7407c14535 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -99,16 +99,19 @@ GridBin::SizeArray GridBin::Setup_Lengths_Center_Spacing(Vec3 const& lengths, Ve return Setup_Sizes_Center_Spacing(nx, ny, nz, center, dxyz); } -/** Assign grid unit cell vectors. */ +/** Apply given unit cell vectors to this grid, keeping the current center + * location. Internal pointers are reset for the new orientation, and the + * potentially new volume and origin coordinates are calculated. + */ void GridBin::Assign_UnitCell( Matrix_3x3 const& unitCell ) { // Save the grid center coords TODO should this just always be saved? Can we skip? Vec3 gridCtrXyz = GridCenter(); box_.SetupFromUcell( unitCell.Dptr() ); SetupInternalPointers(); - set_voxel_volume(); // TODO can we skip this? + set_voxel_volume(); - // Set origin and max // TODO can we skip this? + // Set origin and max SetOriginFromCenter( gridCtrXyz ); } From ebd95c7c707c6117d44922377f2db3aa79ee9946 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 25 Aug 2021 10:25:04 -0400 Subject: [PATCH 68/79] Change from SyncBox to BroadcastBox because thats what actually happens --- src/Box.cpp | 4 ++-- src/Box.h | 2 +- src/CoordinateInfo.cpp | 2 +- src/GridBin.h | 4 ++++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Box.cpp b/src/Box.cpp index 242acf342f..c2435d13f6 100644 --- a/src/Box.cpp +++ b/src/Box.cpp @@ -68,8 +68,8 @@ void Box::swap(Box& rhs) { } #ifdef MPI -/** Sync box info to Comm master. */ -int Box::SyncBox(Parallel::Comm const& commIn) { +/** Broadcast box info from Comm master. */ +int Box::BroadcastBox(Parallel::Comm const& commIn) { commIn.MasterBcast( box_, 6, MPI_DOUBLE ); unitCell_.SyncMatrix( commIn ); fracCell_.SyncMatrix( commIn ); diff --git a/src/Box.h b/src/Box.h index 3edcf96083..b307bc6fab 100644 --- a/src/Box.h +++ b/src/Box.h @@ -24,7 +24,7 @@ class Box { /// SWAP void swap(Box&); # ifdef MPI - int SyncBox(Parallel::Comm const&); + int BroadcastBox(Parallel::Comm const&); int SendBox(int, Parallel::Comm const&) const; int RecvBox(int, Parallel::Comm const&); # endif diff --git a/src/CoordinateInfo.cpp b/src/CoordinateInfo.cpp index d2fcb20b8d..942b80c291 100644 --- a/src/CoordinateInfo.cpp +++ b/src/CoordinateInfo.cpp @@ -181,7 +181,7 @@ int CoordinateInfo::SyncCoordInfo(Parallel::Comm const& commIn) { remdDim_.AddRemdDimension( iArray[ii] ); } delete[] iArray; - box_.SyncBox( commIn ); + box_.BroadcastBox( commIn ); return 0; } #undef CINFOMPISIZE diff --git a/src/GridBin.h b/src/GridBin.h index 57a22f7ff2..393bdcf86c 100644 --- a/src/GridBin.h +++ b/src/GridBin.h @@ -65,6 +65,10 @@ class GridBin { SizeArray Setup_Lengths_Center_Spacing(Vec3 const&, Vec3 const&, Vec3 const&); /// Assign new unit cell vectors to grid void Assign_UnitCell( Matrix_3x3 const& ); +# ifdef MPI + /// Assume split across trajectory; ensure master has orientation from final rank + int Sync(Parallel::Comm const&); +# endif private: inline bool Calc_ortho(double, double, double, size_t&, size_t&, size_t&) const; inline bool Calc_nonortho(double, double, double, size_t&, size_t&, size_t&) const; From b79382e41b092b2597c66881ad8b08167aef1764 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 25 Aug 2021 10:47:28 -0400 Subject: [PATCH 69/79] Change from Sync to broadcast where appropriate --- src/CoordinateInfo.cpp | 6 +++++- src/CoordinateInfo.h | 2 +- src/Traj_AmberCoord.cpp | 4 ++-- src/Traj_CharmmDcd.cpp | 4 ++-- src/Traj_GmxTrX.cpp | 4 ++-- src/TrajectoryIO.cpp | 5 +++-- src/TrajectoryIO.h | 2 +- 7 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/CoordinateInfo.cpp b/src/CoordinateInfo.cpp index 942b80c291..a3b3285ada 100644 --- a/src/CoordinateInfo.cpp +++ b/src/CoordinateInfo.cpp @@ -136,7 +136,11 @@ std::string CoordinateInfo::InfoString() const { #ifdef MPI #define CINFOMPISIZE 12 -int CoordinateInfo::SyncCoordInfo(Parallel::Comm const& commIn) { +/** Broadcast coordinate info from Master. The number of things to be + * broadcast is controlled by CINFOMPISIZE; this must be increased + * if more items added to CoordinateInfo. + */ +int CoordinateInfo::BroadcastCoordInfo(Parallel::Comm const& commIn) { // ensSize, hasvel, hastemp, hastime, hasfrc, NrepDims, Dim1, ..., DimN, int* iArray; int iSize; diff --git a/src/CoordinateInfo.h b/src/CoordinateInfo.h index 107b3df909..4633dc9270 100644 --- a/src/CoordinateInfo.h +++ b/src/CoordinateInfo.h @@ -51,7 +51,7 @@ class CoordinateInfo { /// \return string containing info on present metadata std::string InfoString() const; # ifdef MPI - int SyncCoordInfo(Parallel::Comm const&); + int BroadcastCoordInfo(Parallel::Comm const&); # endif /// \return True if Frame would need to be re-setup based on CoordinateInfo bool operator !=(CoordinateInfo const& rhs) const { diff --git a/src/Traj_AmberCoord.cpp b/src/Traj_AmberCoord.cpp index d4d0893566..28c9382125 100644 --- a/src/Traj_AmberCoord.cpp +++ b/src/Traj_AmberCoord.cpp @@ -468,8 +468,8 @@ int Traj_AmberCoord::parallelSetupTrajout(FileName const& fname, Topology* trajP } commIn.MasterBcast(&err, 1, MPI_INT); if (err != 0) return 1; - // Synchronize info on non-master threads. - SyncTrajIO( commIn ); + // Broadcast info to non-master threads. + BroadcastTrajIO( commIn ); // TODO For simplicity convert everything to double. Is this just lazy? double tmpArray[10]; if (commIn.Master()) { diff --git a/src/Traj_CharmmDcd.cpp b/src/Traj_CharmmDcd.cpp index a447998b23..d9bdb56a6a 100644 --- a/src/Traj_CharmmDcd.cpp +++ b/src/Traj_CharmmDcd.cpp @@ -874,8 +874,8 @@ int Traj_CharmmDcd::parallelSetupTrajout(FileName const& fname, Topology* trajPa } commIn.MasterBcast(&err, 1, MPI_INT); if (err != 0) return 1; - // Synchronize info on non-master threads. - SyncTrajIO( commIn ); + // Broadcast info to non-master threads. + BroadcastTrajIO( commIn ); // TODO for simplicity converting everything to int. Should be double for larger #s? static const unsigned int BCAST_SIZE = 15; std::vector buf( BCAST_SIZE ); diff --git a/src/Traj_GmxTrX.cpp b/src/Traj_GmxTrX.cpp index 0fb4f7d80e..74cadaab24 100644 --- a/src/Traj_GmxTrX.cpp +++ b/src/Traj_GmxTrX.cpp @@ -768,8 +768,8 @@ int Traj_GmxTrX::parallelSetupTrajout(FileName const& fname, Topology* trajParm, } commIn.MasterBcast(&err, 1, MPI_INT); if (err != 0) return 1; - // Synchronize info on non-master threads. - SyncTrajIO( commIn ); + // Broadcast info to non-master threads. + BroadcastTrajIO( commIn ); commIn.MasterBcast( &ir_size_, 1, MPI_INT ); commIn.MasterBcast( &e_size_, 1, MPI_INT ); commIn.MasterBcast( &box_size_, 1, MPI_INT ); diff --git a/src/TrajectoryIO.cpp b/src/TrajectoryIO.cpp index d198a4fd1d..866452ca53 100644 --- a/src/TrajectoryIO.cpp +++ b/src/TrajectoryIO.cpp @@ -1,7 +1,8 @@ #include "TrajectoryIO.h" #ifdef MPI -int TrajectoryIO::SyncTrajIO(Parallel::Comm const& commIn) { - if (coordInfo_.SyncCoordInfo(commIn)) return 1; +/** Broadcast trajectory IO info from master. */ +int TrajectoryIO::BroadcastTrajIO(Parallel::Comm const& commIn) { + if (coordInfo_.BroadcastCoordInfo(commIn)) return 1; int tSize = (int)title_.size(); commIn.MasterBcast( &tSize, 1, MPI_INT ); if (commIn.Master()) diff --git a/src/TrajectoryIO.h b/src/TrajectoryIO.h index 02a87b0e54..660b1cb946 100644 --- a/src/TrajectoryIO.h +++ b/src/TrajectoryIO.h @@ -115,7 +115,7 @@ class TrajectoryIO : public BaseIOtype { int debug_; ///< Trajectory debug level. # ifdef MPI /// Sync up coordinate info etc. - int SyncTrajIO(Parallel::Comm const&); + int BroadcastTrajIO(Parallel::Comm const&); # endif private: CoordinateInfo coordInfo_; ///< Metadata associated with coordinate Frame From ffe338bfbecf6baa498ba088339e69120c2d0a79 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 25 Aug 2021 11:00:50 -0400 Subject: [PATCH 70/79] More function name changes where Broadcast is really meant instead of sync --- src/Box.cpp | 4 ++-- src/Matrix_3x3.cpp | 3 ++- src/Matrix_3x3.h | 2 +- src/NetcdfFile.cpp | 2 +- src/NetcdfFile.h | 2 +- src/Traj_AmberNetcdf.cpp | 4 ++-- src/Traj_NcEnsemble.cpp | 4 ++-- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Box.cpp b/src/Box.cpp index c2435d13f6..3d7d892be7 100644 --- a/src/Box.cpp +++ b/src/Box.cpp @@ -71,8 +71,8 @@ void Box::swap(Box& rhs) { /** Broadcast box info from Comm master. */ int Box::BroadcastBox(Parallel::Comm const& commIn) { commIn.MasterBcast( box_, 6, MPI_DOUBLE ); - unitCell_.SyncMatrix( commIn ); - fracCell_.SyncMatrix( commIn ); + unitCell_.BroadcastMatrix( commIn ); + fracCell_.BroadcastMatrix( commIn ); commIn.MasterBcast( &cellVolume_, 1, MPI_DOUBLE ); return 0; } diff --git a/src/Matrix_3x3.cpp b/src/Matrix_3x3.cpp index f65cb4e4b4..30e58ed386 100644 --- a/src/Matrix_3x3.cpp +++ b/src/Matrix_3x3.cpp @@ -533,7 +533,8 @@ Vec3 Matrix_3x3::AxisOfRotation(double theta) { } #ifdef MPI -void Matrix_3x3::SyncMatrix(Parallel::Comm const& commIn) { +/** Broadcast matrix from master to other ranks. */ +void Matrix_3x3::BroadcastMatrix(Parallel::Comm const& commIn) { commIn.MasterBcast( M_, 9, MPI_DOUBLE ); } diff --git a/src/Matrix_3x3.h b/src/Matrix_3x3.h index 2302a8b5d7..d3fd97b460 100644 --- a/src/Matrix_3x3.h +++ b/src/Matrix_3x3.h @@ -96,7 +96,7 @@ class Matrix_3x3 { const double* Dptr() const { return M_; } double* Dptr() { return M_; } # ifdef MPI - void SyncMatrix(Parallel::Comm const&); + void BroadcastMatrix(Parallel::Comm const&); int SendMatrix(int, Parallel::Comm const&) const; int RecvMatrix(int, Parallel::Comm const&); # endif diff --git a/src/NetcdfFile.cpp b/src/NetcdfFile.cpp index c0936ba514..ac6ccdf47b 100644 --- a/src/NetcdfFile.cpp +++ b/src/NetcdfFile.cpp @@ -1159,7 +1159,7 @@ void NetcdfFile::DebugVIDs() const { } #ifdef MPI -void NetcdfFile::Sync(Parallel::Comm const& commIn) { +void NetcdfFile::Broadcast(Parallel::Comm const& commIn) { static const unsigned int NCVARS_SIZE = 29; int nc_vars[NCVARS_SIZE]; if (commIn.Master()) { diff --git a/src/NetcdfFile.h b/src/NetcdfFile.h index 216b74d9e2..6fd98c209f 100644 --- a/src/NetcdfFile.h +++ b/src/NetcdfFile.h @@ -55,7 +55,7 @@ class NetcdfFile { inline int CoordVID() const { return coordVID_; } protected: // TODO: Make all private # ifdef MPI - void Sync(Parallel::Comm const&); + void Broadcast(Parallel::Comm const&); # endif size_t start_[4]; ///< Array starting indices size_t count_[4]; ///< Array counts diff --git a/src/Traj_AmberNetcdf.cpp b/src/Traj_AmberNetcdf.cpp index 157a7fe14d..3a7da57abf 100644 --- a/src/Traj_AmberNetcdf.cpp +++ b/src/Traj_AmberNetcdf.cpp @@ -461,8 +461,8 @@ int Traj_AmberNetcdf::parallelSetupTrajout(FileName const& fname, Topology* traj } commIn.MasterBcast(&err, 1, MPI_INT); if (err != 0) return 1; - // Synchronize netcdf info on non-master threads. - Sync(commIn); + // Broadcast netcdf info to non-master threads. + Broadcast(commIn); if (!commIn.Master()) { // Non masters need filename and allocate Coord filename_ = fname; diff --git a/src/Traj_NcEnsemble.cpp b/src/Traj_NcEnsemble.cpp index 63dadd227c..bc54c7e91e 100644 --- a/src/Traj_NcEnsemble.cpp +++ b/src/Traj_NcEnsemble.cpp @@ -172,8 +172,8 @@ int Traj_NcEnsemble::setupTrajout(FileName const& fname, Topology* trajParm, # endif if (err != 0) return 1; # ifdef MPI - // Synchronize netcdf info on non-master threads - Sync(Parallel::World()); + // Broadcast netcdf info to non-master threads + Broadcast(Parallel::World()); // DEBUG: Print info for all ranks DebugVIDs(); # endif From c7c4dda542dde2c9e8d2cefbbcfd68d275f09cf1 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 25 Aug 2021 11:01:57 -0400 Subject: [PATCH 71/79] Fix comment --- src/TrajectoryIO.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TrajectoryIO.h b/src/TrajectoryIO.h index 660b1cb946..03d337fe5b 100644 --- a/src/TrajectoryIO.h +++ b/src/TrajectoryIO.h @@ -114,7 +114,7 @@ class TrajectoryIO : public BaseIOtype { void SetCoordInfo(CoordinateInfo const& cIn) { coordInfo_ = cIn; } int debug_; ///< Trajectory debug level. # ifdef MPI - /// Sync up coordinate info etc. + /// Broadcast coordinate info etc. to non-master processes int BroadcastTrajIO(Parallel::Comm const&); # endif private: From c88244a3e22fa310596dc232d02c673a8c2a807b Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 25 Aug 2021 11:32:04 -0400 Subject: [PATCH 72/79] Implement Sync in DataSet_3D so we ensure GridBin sync; have each inheriting class implement summation of the grid. --- src/DataSet_3D.cpp | 10 ++++++++++ src/DataSet_3D.h | 21 +++++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/DataSet_3D.cpp b/src/DataSet_3D.cpp index 138b84eec5..5f9a797c24 100644 --- a/src/DataSet_3D.cpp +++ b/src/DataSet_3D.cpp @@ -134,3 +134,13 @@ void DataSet_3D::GridInfo() const { box.Param(Box::ALPHA), box.Param(Box::BETA), box.Param(Box::GAMMA)); //} } + +#ifdef MPI +/** Sum grid across ranks to master, ensure master has same orientation as final rank. */ +int DataSet_3D::Sync(size_t total, std::vector const& rank_frames, Parallel::Comm const& commIn) +{ + SyncGrid(total, rank_frames, commIn); + gridBin_.Sync( commIn ); + return 0; +} +#endif diff --git a/src/DataSet_3D.h b/src/DataSet_3D.h index dd51af63fa..4169068707 100644 --- a/src/DataSet_3D.h +++ b/src/DataSet_3D.h @@ -18,9 +18,17 @@ class DataSet_3D : public DataSet { /// CONSTRUCTOR - type, format DataSet_3D(DataSet::DataType tIn, TextFormat const& fIn) : DataSet(tIn, GRID_3D, fIn, 3) {} + // ----- DataSet ----------------------------- // TODO enable append? int Append(DataSet*) { return 1; } int Allocate(SizeArray const&) { return 1; } // TODO enable? + // TODO: Remove this. Only needed by DataSet.h + void Add(size_t,const void*) { } +# ifdef MPI + /// Sum grid across ranks to master, ensure orientation from final rank is sent to master. + int Sync(size_t, std::vector const&, Parallel::Comm const&); +# endif + // ------------------------------------------- /// \return Data from grid at x/y/z point. virtual double GetElement(size_t, size_t, size_t) const = 0; /// Set grid to value @@ -44,8 +52,6 @@ class DataSet_3D : public DataSet { /// Divide all elements by the given scalar virtual void operator/=(double) = 0; // ------------------------------------------- - // TODO: Remove this. Only needed by DataSet_1D.h - void Add(size_t,const void*) { } /* double Coord(unsigned int d, size_t p) const { long int idx[3]; @@ -63,6 +69,7 @@ class DataSet_3D : public DataSet { int Allocate_X_C_D(Vec3 const&,Vec3 const&,Vec3 const&); /// Set up grid from dims, origin, and box. int Allocate_N_O_Box(size_t,size_t,size_t, Vec3 const&, Box const&); + /// Move grid center void SetGridCenter(Vec3 const& cxyz) { gridBin_.SetOriginFromCenter( cxyz); } /// Set the grid unit cell @@ -73,8 +80,14 @@ class DataSet_3D : public DataSet { void Xalign_3D_Grid() { gridBin_.X_align_grid(); } /// Print grid info. void GridInfo() const; - // ------------------------------------------- + /// \return GridBin interface GridBin const& Bin() const { return gridBin_; } + // ------------------------------------------- + protected: +# ifdef MPI + /** Used by inheriting class to sum grid across ranks to master. */ + virtual int SyncGrid(size_t, std::vector const&, Parallel::Comm const&) = 0; +# endif private: /// Check if grid dimension is even; if not, increment it by 1. //static void CheckEven(size_t&, char); @@ -84,6 +97,6 @@ class DataSet_3D : public DataSet { /// \return Origin coords from center, spacing, and sizes //static Vec3 calcOriginFromCenter(Vec3 const&, double, double, double, size_t, size_t, size_t); - GridBin gridBin_; ///< Used to calculate bins/coords depending on grid type. + GridBin gridBin_; ///< Used to calculate bins/coords depending on grid orientation. }; #endif From baa36f769c298198cba299cb6439fac9eed099ce Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 25 Aug 2021 11:32:58 -0400 Subject: [PATCH 73/79] Implement GridBin sync --- src/GridBin.cpp | 28 ++++++++++++++++++++++++++++ src/Parallel.h | 4 ++++ 2 files changed, 32 insertions(+) diff --git a/src/GridBin.cpp b/src/GridBin.cpp index 7407c14535..5e81d7d19d 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -175,3 +175,31 @@ void GridBin::X_align_grid() { // with the new grid unit cell. SetOriginFromCenter( gridCtrXyz ); } + +#ifdef MPI +/** Assuming the dataset was split across given comm and that the + * final rank has the final orientation, ensure master rank + * has that orientation/location. Should already have same + * spacing, bin sizes, and volume. + */ +int GridBin::Sync(Parallel::Comm const& commIn) { + int finalRank = commIn.Size() - 1; + if (commIn.Master()) { + commIn.Recv( OXYZ_.Dptr(), 3, MPI_DOUBLE, finalRank, 2000 ); + commIn.Recv( &mx_, 1, MPI_DOUBLE, finalRank, 2001 ); + commIn.Recv( &my_, 1, MPI_DOUBLE, finalRank, 2002 ); + commIn.Recv( &mz_, 1, MPI_DOUBLE, finalRank, 2003 ); + box_.RecvBox( finalRank, commIn ); + // Update internal pointers based on new cell orientation + SetupInternalPointers(); + } else if (commIn.Rank() == finalRank) { + commIn.Send( OXYZ_.Dptr(), 3, MPI_DOUBLE, 0, 2000 ); + commIn.Send( &mx_, 1, MPI_DOUBLE, 0, 2001 ); + commIn.Send( &my_, 1, MPI_DOUBLE, 0, 2002 ); + commIn.Send( &mz_, 1, MPI_DOUBLE, 0, 2003 ); + box_.SendBox( 0, commIn ); + } + commIn.Barrier(); + return 0; +} +#endif diff --git a/src/Parallel.h b/src/Parallel.h index 6beff59e1b..18fed3e199 100644 --- a/src/Parallel.h +++ b/src/Parallel.h @@ -40,6 +40,10 @@ * 1801 : Box::box_ * 1802 : Box::cellVolume_ * 1900 : Matrix_3x3::M_ + * 2000 : GridBin::OXYZ_ + * 2001 : GridBin::mx_ + * 2002 : GridBin::my_ + * 2003 : GridBin::mz_ */ class Parallel { public: From 0d958c0653ea170c0b0f8326b81c9e8d88ff2876 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 25 Aug 2021 11:39:40 -0400 Subject: [PATCH 74/79] Finish new DataSet_3D sync, ensuring GridBin is properly updated on master --- src/DataSet_GridDbl.cpp | 2 +- src/DataSet_GridDbl.h | 9 +++++---- src/DataSet_GridFlt.cpp | 2 +- src/DataSet_GridFlt.h | 9 +++++---- src/GridBin.cpp | 3 +++ 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/DataSet_GridDbl.cpp b/src/DataSet_GridDbl.cpp index c9a4ca4903..993a1cf5f1 100644 --- a/src/DataSet_GridDbl.cpp +++ b/src/DataSet_GridDbl.cpp @@ -22,7 +22,7 @@ void DataSet_GridDbl::WriteBuffer(CpptrajFile& outfile, SizeArray const& pIn) co } #ifdef MPI -int DataSet_GridDbl::Sync(size_t total, std::vector const& rank_frames, +int DataSet_GridDbl::SyncGrid(size_t total, std::vector const& rank_frames, Parallel::Comm const& commIn) { if (commIn.Master()) { diff --git a/src/DataSet_GridDbl.h b/src/DataSet_GridDbl.h index 1025535e53..9eeeedadb4 100644 --- a/src/DataSet_GridDbl.h +++ b/src/DataSet_GridDbl.h @@ -25,10 +25,6 @@ class DataSet_GridDbl : public DataSet_3D { double GridVal(size_t x,size_t y,size_t z) const { return grid_.element(x,y,z); } // ----- DataSet functions ------------------- size_t Size() const { return grid_.size(); } -# ifdef MPI - // TODO: Currently just sums up. Should this be a separate Sync function? - int Sync(size_t, std::vector const&, Parallel::Comm const&); -# endif void Info() const { return; } void WriteBuffer(CpptrajFile&,SizeArray const&) const; size_t MemUsageInBytes() const { return grid_.DataSize(); } @@ -52,6 +48,11 @@ class DataSet_GridDbl : public DataSet_3D { (*it) /= val; } private: +# ifdef MPI + // TODO: Currently just sums up. Should this be a separate Sync function? + int SyncGrid(size_t, std::vector const&, Parallel::Comm const&); +# endif + Grid grid_; }; // ----- INLINE FUNCTIONS ------------------------------------------------------ diff --git a/src/DataSet_GridFlt.cpp b/src/DataSet_GridFlt.cpp index 270a83424c..5996c241cc 100644 --- a/src/DataSet_GridFlt.cpp +++ b/src/DataSet_GridFlt.cpp @@ -22,7 +22,7 @@ void DataSet_GridFlt::WriteBuffer(CpptrajFile& outfile, SizeArray const& pIn) co } #ifdef MPI -int DataSet_GridFlt::Sync(size_t total, std::vector const& rank_frames, +int DataSet_GridFlt::SyncGrid(size_t total, std::vector const& rank_frames, Parallel::Comm const& commIn) { if (commIn.Master()) { diff --git a/src/DataSet_GridFlt.h b/src/DataSet_GridFlt.h index 12740dabae..cb10afd961 100644 --- a/src/DataSet_GridFlt.h +++ b/src/DataSet_GridFlt.h @@ -25,10 +25,6 @@ class DataSet_GridFlt : public DataSet_3D { float GridVal(size_t x,size_t y,size_t z) const { return grid_.element(x,y,z); } // ----- DataSet functions ------------------- size_t Size() const { return grid_.size(); } -# ifdef MPI - // TODO: Currently just sums up. Should this be a separate Sync function? - int Sync(size_t, std::vector const&, Parallel::Comm const&); -# endif void Info() const { return; } void WriteBuffer(CpptrajFile&,SizeArray const&) const; size_t MemUsageInBytes() const { return grid_.DataSize(); } @@ -54,6 +50,11 @@ class DataSet_GridFlt : public DataSet_3D { } private: +# ifdef MPI + // TODO: Currently just sums up. Should this be a separate Sync function? + int SyncGrid(size_t, std::vector const&, Parallel::Comm const&); +# endif + Grid grid_; }; // ----- INLINE FUNCTIONS ------------------------------------------------------ diff --git a/src/GridBin.cpp b/src/GridBin.cpp index 5e81d7d19d..af89aa1cf9 100644 --- a/src/GridBin.cpp +++ b/src/GridBin.cpp @@ -183,6 +183,9 @@ void GridBin::X_align_grid() { * spacing, bin sizes, and volume. */ int GridBin::Sync(Parallel::Comm const& commIn) { + // If only 1 rank no need for this. + if (commIn.Size() < 2) return 0; + // Determine final rank int finalRank = commIn.Size() - 1; if (commIn.Master()) { commIn.Recv( OXYZ_.Dptr(), 3, MPI_DOUBLE, finalRank, 2000 ); From dc39f7aa50f744f119433cdbd12d098c89b13b03 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 25 Aug 2021 11:44:40 -0400 Subject: [PATCH 75/79] Improve comment --- src/GridAction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GridAction.h b/src/GridAction.h index bef156960d..3cb474267f 100644 --- a/src/GridAction.h +++ b/src/GridAction.h @@ -77,7 +77,7 @@ const } } -/** Move grid if necessary. */ +/** Move/reorient grid if necessary. */ void GridAction::MoveGrid(Frame const& currentFrame, DataSet_GridFlt& grid) { if (gridMoveType_ == TO_BOX_CTR) From 8a80e5c57f76e94e9f141b084b47947431a4cb30 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 25 Aug 2021 12:35:28 -0400 Subject: [PATCH 76/79] Add noxalign keyword. Hide some debug info --- src/GridAction.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/GridAction.cpp b/src/GridAction.cpp index c89c40a99d..2764278093 100644 --- a/src/GridAction.cpp +++ b/src/GridAction.cpp @@ -19,7 +19,7 @@ const char* GridAction::HelpText = "\t [ { gridcenter |\n" "\t boxcenter |\n" "\t maskcenter |\n" - "\t rmsfit } ]\n" + "\t rmsfit [noxalign]} ]\n" "\t[box|origin|center ] [negative] [name ]"; static inline void CheckEven(int& N, char dir) { @@ -34,6 +34,7 @@ DataSet_GridFlt* GridAction::GridInit(const char* callingRoutine, ArgList& argIn { DataSet_GridFlt* Grid = 0; bool specifiedCenter = false; + x_align_ = !argIn.hasKey("noxalign"); std::string dsname = argIn.GetStringKey("data"); std::string refname = argIn.GetStringKey("boxref"); if (!dsname.empty()) { @@ -178,9 +179,14 @@ void GridAction::GridInfo(DataSet_GridFlt const& grid) { else if (gridMoveType_ == TO_MASK_CTR) mprintf("\tGrid will be kept centered on atoms in mask [%s]\n", centerMask_.MaskString()); - else if (gridMoveType_ == RMS_FIT) + else if (gridMoveType_ == RMS_FIT) { mprintf("\tGrid will be RMS-fit using atoms in mask [%s]\n", centerMask_.MaskString()); + if (x_align_) + mprintf("\tGrid will be realigned with Cartesian axes after binning is complete.\n"); + else + mprintf("\tGrid will not be realigned with Cartesian axes after binning is complete.\n"); + } if (increment_ > 0) mprintf("\tCalculating positive density.\n"); else @@ -227,14 +233,14 @@ int GridAction::SetTgt(Frame const& frameIn, Matrix_3x3 const& gridUcell) trajComm_.MasterBcast( tgt_.xAddress(), tgt_.size(), MPI_DOUBLE ); // Ensure all threads have the same unit cell vecs trajComm_.MasterBcast( tgtUcell_.Dptr(), 9, MPI_DOUBLE ); - rprintf("DEBUG: Ucell0: %f %f %f %f %f %f %f %f %f\n", tgtUcell_[0], tgtUcell_[1], tgtUcell_[2], tgtUcell_[3], tgtUcell_[4], tgtUcell_[5], tgtUcell_[6], tgtUcell_[7], tgtUcell_[8]); + //rprintf("DEBUG: Ucell0: %f %f %f %f %f %f %f %f %f\n", tgtUcell_[0], tgtUcell_[1], tgtUcell_[2], tgtUcell_[3], tgtUcell_[4], tgtUcell_[5], tgtUcell_[6], tgtUcell_[7], tgtUcell_[8]); # endif return 0; } /** Any final actions to grid. */ void GridAction::FinishGrid(DataSet_GridFlt& grid) const { - rprintf("DEBUG: Final Grid origin: %f %f %f\n", grid.Bin().GridOrigin()[0], grid.Bin().GridOrigin()[1], grid.Bin().GridOrigin()[2]); + //rprintf("DEBUG: Final Grid origin: %f %f %f\n", grid.Bin().GridOrigin()[0], grid.Bin().GridOrigin()[1], grid.Bin().GridOrigin()[2]); if (x_align_) { if (!grid.Bin().IsXalignedGrid()) { mprintf("\tEnsuring grid '%s' is X-aligned.\n", grid.legend()); From de342d85bd793ea72fc892f2d54108907ca65ab8 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 25 Aug 2021 12:45:20 -0400 Subject: [PATCH 77/79] Fix dipole manual entry. Add 'noxalign' to grid entry. --- doc/cpptraj.lyx | 233 ++++++++++++++++++++++++++++++++++++++++-- src/Action_Dipole.cpp | 2 +- 2 files changed, 223 insertions(+), 12 deletions(-) diff --git a/doc/cpptraj.lyx b/doc/cpptraj.lyx index 837e709631..d367e77aec 100644 --- a/doc/cpptraj.lyx +++ b/doc/cpptraj.lyx @@ -22983,11 +22983,11 @@ dipole \end_layout \begin_layout LyX-Code -dipole +dipole [out ] \end_layout \begin_layout LyX-Code - { data | boxref | + { data | boxref | \end_layout \begin_layout LyX-Code @@ -22995,19 +22995,19 @@ dipole \end_layout \begin_layout LyX-Code - [ { gridcenter | + [ { gridcenter | \end_layout \begin_layout LyX-Code - boxcenter | + boxcenter | \end_layout \begin_layout LyX-Code - maskcenter | + maskcenter | \end_layout \begin_layout LyX-Code - rmsfit } ] + rmsfit [noxalign]} ] \end_layout \begin_layout LyX-Code @@ -23015,15 +23015,213 @@ dipole \end_layout \begin_layout LyX-Code - {origin | box} [max ] + [max ] \end_layout +\begin_deeper +\begin_layout Description +[out +\begin_inset space ~ +\end_inset + +] File to write out grid to. + Use +\begin_inset Quotes eld +\end_inset + +.grid +\begin_inset Quotes erd +\end_inset + + or +\begin_inset Quotes eld +\end_inset + +.xplor +\begin_inset Quotes erd +\end_inset + + extension for XPLOR format, +\begin_inset Quotes eld +\end_inset + +.dx +\begin_inset Quotes erd +\end_inset + + for OpenDX format. +\end_layout + +\begin_layout Standard +Options for setting up grid: +\end_layout + +\begin_layout Description +data +\begin_inset space ~ +\end_inset + + Use previously calculated/loaded grid data set named . + When using this option there is no need to specify grid bins/spacing/center. +\end_layout + +\begin_layout Description +boxref +\begin_inset space ~ +\end_inset + + +\begin_inset space ~ +\end_inset + + +\begin_inset space ~ +\end_inset + + +\begin_inset space ~ +\end_inset + + Set up grid using box information from a previously loaded reference + structure. + Currently the only way to set up non-orthogonal grids. +\end_layout + +\begin_layout Description + +\begin_inset space ~ +\end_inset + + +\begin_inset space ~ +\end_inset + + +\begin_inset space ~ +\end_inset + + +\begin_inset space ~ +\end_inset + + +\begin_inset space ~ +\end_inset + + Number of grid bins and spacing in the X/Y/Z directions. +\end_layout + +\begin_layout Description +[gridcenter +\begin_inset space ~ +\end_inset + + +\begin_inset space ~ +\end_inset + + +\begin_inset space ~ +\end_inset + +] Location of grid center, default is origin (0.0, 0.0, 0.0). +\end_layout + +\begin_layout Description +[boxcenter] Center grid on box center. +\end_layout + +\begin_layout Description +[maskcenter +\begin_inset space ~ +\end_inset + +] Center the grid on the atoms selected by . +\end_layout + +\begin_layout Description +[rmsfit +\begin_inset space ~ +\end_inset + +] Perform a best-fit rotation of the grid using the coordinates selected + by . +\end_layout + +\begin_deeper +\begin_layout Description +[noxalign] If specified, grid will not be re-oriented to align with Cartesian + axes once binning is finished. + Will affect file formats that do not store full unit cell vectors (like + Xplor). +\end_layout + +\end_deeper +\begin_layout Standard +Options for offset during grid binning (must center grid at origin): +\end_layout + +\begin_layout Description +[box] Offset each point by location of box center prior to gridding. + Cannot be used with 'gridcenter'. +\end_layout + +\begin_layout Description +[origin] No offset (default) +\end_layout + +\begin_layout Description +[center +\begin_inset space ~ +\end_inset + +] Offset each point by center of atoms in prior to gridding. + Cannot be used with 'gridcenter'. +\end_layout + +\begin_layout Standard +Other options: +\end_layout + +\begin_layout Description +[negative] Grid negative density instead of positive density. +\end_layout + +\begin_layout Description +[name +\begin_inset space ~ +\end_inset + +] Grid data set name. +\end_layout + +\begin_layout Description + Mask selecting solvent atoms to bin. +\end_layout + +\begin_layout Description +[max +\begin_inset space ~ +\end_inset + +] Only keep density >= to of the maximum density. +\end_layout + +\end_deeper \begin_layout Standard NOTE: This command is not well-tested and may be obsolete. \end_layout \begin_layout Standard -Same as +Similar to \family sans \series bold grid @@ -26242,7 +26440,7 @@ name "subsec:cpptraj_grid" \end_layout \begin_layout LyX-Code -grid +grid [out ] \end_layout \begin_layout LyX-Code @@ -26266,7 +26464,7 @@ grid \end_layout \begin_layout LyX-Code - rmsfit } ] + rmsfit [noxalign]} ] \end_layout \begin_layout LyX-Code @@ -26291,7 +26489,11 @@ grid \begin_deeper \begin_layout Description - File to write out grid to. +[out +\begin_inset space ~ +\end_inset + +] File to write out grid to. Use \begin_inset Quotes eld \end_inset @@ -26419,6 +26621,15 @@ name/tag> by . \end_layout +\begin_deeper +\begin_layout Description +[noxalign] If specified, grid will not be re-oriented to align with Cartesian + axes once binning is finished. + Will affect file formats that do not store full unit cell vectors (like + Xplor). +\end_layout + +\end_deeper \begin_layout Standard Options for offset during grid binning (must center grid at origin): \end_layout diff --git a/src/Action_Dipole.cpp b/src/Action_Dipole.cpp index 126d9fe8cd..cbed3dfe36 100644 --- a/src/Action_Dipole.cpp +++ b/src/Action_Dipole.cpp @@ -59,7 +59,7 @@ Action::RetType Action_Dipole::Init(ArgList& actionArgs, ActionInit& init, int d mprintf("\tGrid will be printed to file %s\n",outfile_->Filename().full()); mprintf("\tMask expression: [%s]\n",mask_.MaskString()); if (max_ > 0) - mprintf("\tOnly keeping density >= to %.0lf%% of the maximum density\n", max_); + mprintf("\tOnly keeping density >= to %.0f%% of the maximum density\n", max_); return Action::OK; } From 451d0425310553d2e64aeccb318151285b0becea Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 25 Aug 2021 13:00:35 -0400 Subject: [PATCH 78/79] Hide some debug info --- src/DataSet_3D.cpp | 8 ++++++++ src/DataSet_3D.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/DataSet_3D.cpp b/src/DataSet_3D.cpp index 5f9a797c24..b8fa50a9f1 100644 --- a/src/DataSet_3D.cpp +++ b/src/DataSet_3D.cpp @@ -33,7 +33,9 @@ int DataSet_3D::Allocate_N_O_Box(size_t nx, size_t ny, size_t nz, } // Set origin and unit cell params. gridBin_.Setup_Sizes_Origin_Box(nx, ny, nz, oxyz, boxIn); +# ifdef DEBUG_DATASET_3D gridBin_.PrintDebug("Allocate_N_O_Box"); +# endif return Allocate3D(nx, ny, nz); } @@ -47,7 +49,9 @@ int DataSet_3D::Allocate_N_O_D(size_t nx, size_t ny, size_t nz, } // Set origin and spacing, calculate maximum (for binning). gridBin_.Setup_Sizes_Origin_Spacing(nx, ny, nz, oxyz, dxyz); +# ifdef DEBUG_DATASET_3D gridBin_.PrintDebug("Allocate_N_O_D"); +# endif return Allocate3D(nx, ny, nz); } @@ -83,7 +87,9 @@ int DataSet_3D::Allocate_N_C_D(size_t nx, size_t ny, size_t nz, { // Calculate origin from center coordinates. gridBin_.Setup_Sizes_Center_Spacing(nx, ny, nz, cxyz, dxyz); +# ifdef DEBUG_DATASET_3D gridBin_.PrintDebug("Allocate_N_C_D"); +# endif return Allocate3D(nx, ny, nz); /* return Allocate_N_O_D(nx, ny, nz, calcOriginFromCenter(cxyz, dxyz[0], dxyz[1], dxyz[2], nx, ny, nz), @@ -104,7 +110,9 @@ int DataSet_3D::Allocate_X_C_D(Vec3 const& sizes, Vec3 const& center, Vec3 const size_t nz = (size_t)ceil(sizes[2] / dxyz[2]); return Allocate_N_C_D( nx, ny, nz, center, dxyz );*/ GridBin::SizeArray gridSizes = gridBin_.Setup_Lengths_Center_Spacing(sizes, center, dxyz); +# ifdef DEBUG_DATASET_3D gridBin_.PrintDebug("Allocate_X_C_D"); +# endif return Allocate3D(gridSizes[0], gridSizes[1], gridSizes[2]); } diff --git a/src/DataSet_3D.h b/src/DataSet_3D.h index 4169068707..44b12ba555 100644 --- a/src/DataSet_3D.h +++ b/src/DataSet_3D.h @@ -5,6 +5,7 @@ #include "GridBin.h" class Box; /// Interface for 3D DataSets. +/** Compile with -DDEBUG_DATASET_3D to print debug info during allocation. */ // TODO: Use DataSet Dims? class DataSet_3D : public DataSet { public: From 17f1dbef0505b95305b289ebfeeecb51e55b7187 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Wed, 25 Aug 2021 14:47:56 -0400 Subject: [PATCH 79/79] Revision bump; addition of rotatable grids via rms fitting. Addition of gridset keyword for 'vector' command. --- src/Version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.h b/src/Version.h index ee56b94062..d3cd984d75 100644 --- a/src/Version.h +++ b/src/Version.h @@ -12,7 +12,7 @@ * Whenever a number that precedes is incremented, all subsequent * numbers should be reset to 0. */ -#define CPPTRAJ_INTERNAL_VERSION "V5.4.0" +#define CPPTRAJ_INTERNAL_VERSION "V5.4.1" /// PYTRAJ relies on this #define CPPTRAJ_VERSION_STRING CPPTRAJ_INTERNAL_VERSION #endif