Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
a9e7744
Start converting GridBin class from abstract base class to full
drroe Jun 23, 2021
c3d4c68
Implement GridBin Indices, Center, and Corner
drroe Jun 23, 2021
2eba0cf
Finish initial conversion of GridBin
drroe Jun 23, 2021
aba1787
Add orthogonal setup routine.
drroe Jun 23, 2021
7b891a0
Add setup from origin and box
drroe Jun 23, 2021
06b85de
Modify DataSet_3D to use new GridBin
drroe Jun 23, 2021
16e7ba0
Modify for new gridbin
drroe Jun 23, 2021
b27a65b
Apparently these need to be explicitly inlined
drroe Jun 23, 2021
0527830
Add debug for Setup_O_Box
drroe Jun 23, 2021
42ca1c1
Add some debug info, commented out for now.
drroe Jun 24, 2021
02f7e80
Remove cast to GridBin
drroe Jun 24, 2021
0ad220a
Use class function pointers in GridBin to avoid 'if' branching, restores
drroe Jun 24, 2021
42f3291
Add function pointers for corner and center
drroe Jun 24, 2021
5cd4ab6
Start adding ability to extract box params from grid instead of frame
drroe Jun 25, 2021
d6074b9
Add BoxLengths function
drroe Jun 25, 2021
5369c05
Use BoxLengths function
drroe Jun 25, 2021
acf34ad
Use gridSet where appropriate
drroe Jun 25, 2021
bd557af
Fix origin for ucell vecs from grids
drroe Jun 25, 2021
dedd422
Add gridset keyword to vector documentation
drroe Jun 25, 2021
0a71203
Change GridMode to OffsetType, better describes what it is actually used
drroe Jun 25, 2021
672f0ab
Create calcOriginFromCenter function, add missing include cstddef
drroe Jun 25, 2021
fde347c
Add SetOrigin function
drroe Jun 25, 2021
3ea2a4c
Start adding code to move the grid
drroe Jun 25, 2021
e6ae011
Add boxcenter and maskcenter keywords
drroe Jun 25, 2021
32dfbfe
Ensure mask is set up. Add MoveGrid calls to GridAction actions
drroe Jun 25, 2021
5561d1d
Add info on grid move type
drroe Jun 25, 2021
83469fd
Create GridBin source file
drroe Jun 28, 2021
80887ae
Fix max determination
drroe Jun 28, 2021
d9b83c3
Add function to set new origin from center
drroe Jun 28, 2021
45d9eb5
Add X-aligned ortho case
drroe Jun 29, 2021
fc581a2
Start moving allocation logic from DataSet_3D to GridBin
drroe Jun 29, 2021
6305a50
Clean up, add sizes/center/spacing
drroe Jun 29, 2021
8087866
Add routine with lengths, center, spacing
drroe Jun 29, 2021
247f7be
Use the new GridBin setup routines
drroe Jun 29, 2021
da6554c
Add separate debug routine
drroe Jun 29, 2021
a5ccb2a
Add missing var
drroe Jun 29, 2021
f1a7451
Fix calculation of grid center. Fix info print about centering.
drroe Jun 29, 2021
751db98
Fix class description
drroe Jun 29, 2021
2b196b6
Fix up variable descriptions
drroe Jun 29, 2021
a394d35
Add trans rot trans to Matrix_3x3
drroe Jun 29, 2021
cfce450
Add function to set up box from 3 unit cell vectors
drroe Jun 29, 2021
a7c3339
First attempt to get function that can rotate the grid, not efficient
drroe Jun 29, 2021
db5572d
Create MoveType
drroe Jun 29, 2021
192850c
Fix typo
drroe Jun 29, 2021
af3a436
Allow DataSet_3D grid to be rotated
drroe Jun 29, 2021
9a53b64
Implement the rmsfit keyword for grids
drroe Jun 29, 2021
126b7a3
Only rotate the unit cell and set up pointers
drroe Jun 30, 2021
06b5811
Walk back some unused changes
drroe Jun 30, 2021
41e98ab
Trim up the grid rotation function call
drroe Jun 30, 2021
26edcfd
Properly handle rotation of origin coord
drroe Jul 2, 2021
d97133f
Remove bad code
drroe Jul 2, 2021
eebd3a8
Comment out unused code
drroe Jul 2, 2021
e806acd
Function to X-align the grid
drroe Jul 2, 2021
f7a185f
Create Xalign_3D_Grid function
drroe Jul 2, 2021
b4550b8
Add function to ensure grid is x-aligned at the end of processing
drroe Jul 2, 2021
772d12b
Add FinishGrid to all grid actions
drroe Jul 2, 2021
6eb20ad
Print informative message if grid is being X-aligned
drroe Jul 2, 2021
9253202
Fix x-align check
drroe Jul 2, 2021
d0a728c
Store number of frames in separate variable in case we are catting to
drroe Jul 6, 2021
495501f
Merge branch 'master' into rotategrid
drroe Jul 26, 2021
29fc1a1
Merge branch 'master' into rotategrid
drroe Aug 18, 2021
3933be1
Merge branch 'master' into rotategrid
drroe Aug 23, 2021
3e15e8c
Instead of rotating the grid from previous to current frame, rotate from
drroe Aug 24, 2021
5652124
Add test for grid rms fit and grid centering
drroe Aug 24, 2021
57df63c
Enable the grid rotate test
drroe Aug 24, 2021
4654e94
Update help for grid
drroe Aug 24, 2021
dd61694
Add some examples for grid rmsfit and maskcenter
drroe Aug 24, 2021
919072e
Disable progress bar for easier debug
drroe Aug 24, 2021
a618db4
Start fixing gridaction rotation with multiple procs
drroe Aug 24, 2021
f520adf
Fix code comments
drroe Aug 25, 2021
ebd95c7
Change from SyncBox to BroadcastBox because thats what actually happens
drroe Aug 25, 2021
b79382e
Change from Sync to broadcast where appropriate
drroe Aug 25, 2021
ffe338b
More function name changes where Broadcast is really meant instead of…
drroe Aug 25, 2021
c7c4dda
Fix comment
drroe Aug 25, 2021
c88244a
Implement Sync in DataSet_3D so we ensure GridBin sync; have each
drroe Aug 25, 2021
baa36f7
Implement GridBin sync
drroe Aug 25, 2021
0d958c0
Finish new DataSet_3D sync, ensuring GridBin is properly updated on
drroe Aug 25, 2021
dc39f7a
Improve comment
drroe Aug 25, 2021
8a80e5c
Add noxalign keyword. Hide some debug info
drroe Aug 25, 2021
de342d8
Fix dipole manual entry. Add 'noxalign' to grid entry.
drroe Aug 25, 2021
451d042
Hide some debug info
drroe Aug 25, 2021
17f1dbe
Revision bump; addition of rotatable grids via rms fitting. Addition of
drroe Aug 25, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
350 changes: 338 additions & 12 deletions doc/cpptraj.lyx

Large diffs are not rendered by default.

13 changes: 9 additions & 4 deletions src/Action_Dipole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -104,12 +104,15 @@ 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 (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.
Expand Down Expand Up @@ -187,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
Expand Down
9 changes: 6 additions & 3 deletions src/Action_Grid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,13 @@ 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 (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)
Expand All @@ -146,7 +148,8 @@ 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;
if (normalize_ == NONE) {
Expand Down
4 changes: 4 additions & 0 deletions src/Action_GridFreeEnergy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,16 @@ 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;
}

// 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
Expand Down
52 changes: 43 additions & 9 deletions src/Action_Vector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -20,12 +22,12 @@ Action_Vector::Action_Vector() :
// Action_Vector::Help()
void Action_Vector::Help() const {
mprintf("\t[<name>] <Type> [out <filename> [ptrajoutput]] [<mask1>] [<mask2>]\n"
"\t[magnitude] [ired]\n"
"\t[magnitude] [ired] [gridset <grid>]\n"
"\t<Type> = { 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 <mask1> to <mask2>.\n"
" Calculate the vector of specified <Type>:\n"
" mask : (Default) Vector from <mask1> to <mask2>.\n"
" minimage : Store the minimum image vector between atoms in <mask1> and <mask2>.\n"
" dipole : Dipole and center of mass of the atoms specified in <mask1>\n"
" center : Store the center of mass of atoms in <mask1>.\n"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -418,16 +437,21 @@ 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;
}
}

/** 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_);
Expand Down Expand Up @@ -461,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 : Vec_->AddVxyz( frm.Frm().BoxCrd().Lengths() ); 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(), gridSet_->Bin().GridOrigin() );
else
UnitCell( frm.Frm().BoxCrd(), Vec3(0.0) );
break;
case MINIMAGE : MinImage( frm.Frm() ); break;
default : return Action::ERR; // NO_OP
} // END switch over vectorMode
Expand Down
5 changes: 4 additions & 1 deletion src/Action_Vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -29,11 +30,13 @@ 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&);

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
Expand Down
9 changes: 4 additions & 5 deletions src/Action_Volmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_Ortho const& gbo = static_cast<GridBin_Ortho const&>( 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];
Expand Down
8 changes: 4 additions & 4 deletions src/Box.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ 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 );
unitCell_.BroadcastMatrix( commIn );
fracCell_.BroadcastMatrix( commIn );
commIn.MasterBcast( &cellVolume_, 1, MPI_DOUBLE );
return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Box.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions src/CoordinateInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -181,7 +185,7 @@ int CoordinateInfo::SyncCoordInfo(Parallel::Comm const& commIn) {
remdDim_.AddRemdDimension( iArray[ii] );
}
delete[] iArray;
box_.SyncBox( commIn );
box_.BroadcastBox( commIn );
return 0;
}
#undef CINFOMPISIZE
Expand Down
2 changes: 1 addition & 1 deletion src/CoordinateInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
32 changes: 14 additions & 18 deletions src/DataIO_Std.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<GridBin_Nonortho const&>( 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<GridBin_Ortho const&>( 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)
Expand Down Expand Up @@ -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<GridBin_Ortho const&>( 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<GridBin_Nonortho const&>( 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());
Expand Down
Loading