@@ -3956,7 +3956,7 @@ namespace BasisClasses
39563956
39573957 // Generate coeffients from a particle reader
39583958 CoefClasses::CoefStrPtr BiorthBasis::createFromReader
3959- (PR::PRptr reader, std::vector< double > ctr)
3959+ (PR::PRptr reader, Eigen::Vector3d ctr, RowMatrix3d rot )
39603960 {
39613961 CoefClasses::CoefStrPtr coef;
39623962
@@ -3975,44 +3975,55 @@ namespace BasisClasses
39753975 throw std::runtime_error (sout.str ());
39763976 }
39773977
3978- // Is center non-zero?
3978+ // Add the expansion center metadata and register for this instance
39793979 //
3980- bool addCenter = false ;
3981- for (auto v : ctr) {
3982- if (v != 0.0 ) addCenter = true ;
3983- }
3980+ coefctr = ctr;
3981+ coef->ctr = ctr;
39843982
3985- // Add the expansion center metadata
3983+ // Add the rotation matrix metadata and register for this instance
39863984 //
3987- if (addCenter) coef->ctr = ctr;
3985+ coefrot = rot;
3986+ coef->rot = rot;
39883987
3989- std::vector<double > pp (3 ), vv (3 );
3988+ std::vector<double > p1 (3 ), v1 (3 );
3989+
3990+ // Map the vector rather than copy
3991+ //
3992+ Eigen::Map<Eigen::Vector3d> pp (p1.data (), 3 ), vv (v1.data (), 3 );
3993+ vv.setZero ();
39903994
39913995 reset_coefs ();
39923996 for (auto p=reader->firstParticle (); p!=0 ; p=reader->nextParticle ()) {
39933997
39943998 bool use = false ;
39953999
4000+ // Translate and rotate the position vector
4001+ //
4002+ for (int k=0 ; k<3 ; k++) p1[k] = p->pos [k];
4003+ pp = coefrot * (pp - coefctr);
4004+
39964005 if (ftor) {
3997- pp.assign (p->pos , p->pos +3 );
3998- vv.assign (p->vel , p->vel +3 );
3999- use = ftor (p->mass , pp, vv, p->indx );
4006+ // Rotate the velocity vector
4007+ //
4008+ for (int k=0 ; k<3 ; k++) v1[k] = p->vel [k];
4009+ vv = coefrot * vv;
4010+
4011+ use = ftor (p->mass , p1, v1, p->indx );
40004012 } else {
40014013 use = true ;
40024014 }
40034015
4004- if (use) accumulate (p->pos [0 ]-ctr[0 ],
4005- p->pos [1 ]-ctr[1 ],
4006- p->pos [2 ]-ctr[2 ],
4007- p->mass );
4016+ if (use) {
4017+ accumulate (pp (0 ), pp (1 ), pp (2 ), p->mass );
4018+ }
40084019 }
40094020 make_coefs ();
40104021 load_coefs (coef, reader->CurrentTime ());
40114022 return coef;
40124023 }
40134024
40144025 // Generate coefficients from a phase-space table
4015- void BiorthBasis::initFromArray (std::vector< double > ctr)
4026+ void BiorthBasis::initFromArray (Eigen::Vector3d ctr, RowMatrix3d rot )
40164027 {
40174028 if (name.compare (" sphereSL" ) == 0 )
40184029 coefret = std::make_shared<CoefClasses::SphStruct>();
@@ -4027,20 +4038,14 @@ namespace BasisClasses
40274038 throw std::runtime_error (sout.str ());
40284039 }
40294040
4030- // Is center non-zero?
4031- //
4032- bool addCenter = false ;
4033- for (auto v : ctr) {
4034- if (v != 0.0 ) addCenter = true ;
4035- }
4036-
4037- // Add the expansion center metadata
4038- //
4039- if (addCenter) coefret->ctr = ctr;
4040-
4041- // Register the center
4041+ // Add the expansion center metadata and register
40424042 //
40434043 coefctr = ctr;
4044+ coefret->ctr = ctr;
4045+
4046+ // Add the rotation metadata and register
4047+ coefrot = rot;
4048+ coefret->rot = rot;
40444049
40454050 // Clean up for accumulation
40464051 //
@@ -4069,6 +4074,7 @@ namespace BasisClasses
40694074 int cols = p.cols ();
40704075
40714076 bool ambiguous = false ;
4077+ bool haveVel = false ;
40724078
40734079 if (cols==3 or cols==6 ) {
40744080 if (rows != 3 and rows != 6 ) PosVelRows = false ;
@@ -4089,7 +4095,11 @@ namespace BasisClasses
40894095 << " if this assumption is wrong." << std::endl;
40904096 }
40914097
4092- std::vector<double > p1 (3 ), v1 (3 , 0 );
4098+ // Map the vector rather than copy
4099+ //
4100+ std::vector<double > p1 (3 ), v1 (3 );
4101+ Eigen::Map<Eigen::Vector3d> pp (p1.data (), 3 ), vv (v1.data (), 3 );
4102+ vv.setZero ();
40934103
40944104 if (PosVelRows) {
40954105 if (p.rows ()<3 ) {
@@ -4099,22 +4109,32 @@ namespace BasisClasses
40994109 throw std::runtime_error (msg.str ());
41004110 }
41014111
4102- for ( int n= 0 ; n<p. cols (); n++) {
4112+ if (p. rows () == 6 ) haveVel = true ;
41034113
4114+ for (int n=0 ; n<p.cols (); n++) {
4115+
41044116 if (n % numprocs==myid or not RoundRobin) {
41054117
4118+ for (int k=0 ; k<3 ; k++) {
4119+ pp (k) = p (k, n);
4120+ if (haveVel) vv (k) = p (k+3 , n);
4121+ }
4122+
4123+ pp = coefrot * (pp - coefctr);
4124+
41064125 bool use = true ;
4126+
41074127 if (ftor) {
4108- for ( int k= 0 ; k< 3 ; k++) p1[k] = p (k, n) ;
4128+ if (haveVel) vv = coefrot * vv ;
41094129 use = ftor (m (n), p1, v1, coefindx);
41104130 } else {
41114131 use = true ;
41124132 }
41134133 coefindx++;
41144134
4115- if (use) accumulate ( p ( 0 , n)-coefctr[ 0 ],
4116- p ( 1 , n)-coefctr[ 1 ],
4117- p ( 2 , n)-coefctr[ 2 ], m (n));
4135+ if (use) {
4136+ accumulate ( pp ( 0 ), pp ( 1 ), pp ( 2 ), m (n));
4137+ }
41184138 }
41194139 }
41204140
@@ -4127,22 +4147,32 @@ namespace BasisClasses
41274147 throw std::runtime_error (msg.str ());
41284148 }
41294149
4150+ if (p.cols () == 6 ) haveVel = true ;
4151+
4152+
41304153 for (int n=0 ; n<p.rows (); n++) {
41314154
41324155 if (n % numprocs==myid or not RoundRobin) {
41334156
4157+ for (int k=0 ; k<3 ; k++) {
4158+ pp (k) = p (n, k);
4159+ if (haveVel) vv (k) = p (n, k+3 );
4160+ }
4161+
4162+ pp = coefrot * (pp - coefctr);
4163+
41344164 bool use = true ;
41354165 if (ftor) {
4136- for ( int k= 0 ; k< 3 ; k++) p1[k] = p (n, k) ;
4166+ if (haveVel) vv = coefrot * vv ;
41374167 use = ftor (m (n), p1, v1, coefindx);
41384168 } else {
41394169 use = true ;
41404170 }
41414171 coefindx++;
41424172
4143- if (use) accumulate ( p (n, 0 )-coefctr[ 0 ],
4144- p (n, 1 )-coefctr[ 1 ],
4145- p (n, 2 )-coefctr[ 2 ], m (n));
4173+ if (use) {
4174+ accumulate ( pp ( 0 ), pp ( 1 ), pp ( 2 ), m (n));
4175+ }
41464176 }
41474177 }
41484178 }
@@ -4159,10 +4189,10 @@ namespace BasisClasses
41594189 // Generate coefficients from a phase-space table
41604190 //
41614191 CoefClasses::CoefStrPtr BiorthBasis::createFromArray
4162- (Eigen::VectorXd& m, RowMatrixXd& p, double time, std::vector< double > ctr,
4163- bool RoundRobin, bool PosVelRows)
4192+ (Eigen::VectorXd& m, RowMatrixXd& p, double time, Eigen::Vector3d ctr,
4193+ RowMatrix3d rot, bool RoundRobin, bool PosVelRows)
41644194 {
4165- initFromArray (ctr);
4195+ initFromArray (ctr, rot );
41664196 addFromArray (m, p, RoundRobin, PosVelRows);
41674197 return makeFromArray (time);
41684198 }
@@ -4180,13 +4210,20 @@ namespace BasisClasses
41804210 auto ctr = basis->getCenter ();
41814211 if (basis->usingNonInertial ()) ctr = {0 , 0 , 0 };
41824212
4213+ // Get rotation matrix
4214+ //
4215+ auto rot = basis->getRotation ();
4216+
41834217 // Get fields
41844218 //
41854219 int rows = accel.rows ();
41864220 for (int n=0 ; n<rows; n++) {
4187- auto v = basis->getFields (ps (n, 0 ) - ctr[0 ],
4188- ps (n, 1 ) - ctr[1 ],
4189- ps (n, 2 ) - ctr[2 ]);
4221+ Eigen::Vector3d pp;
4222+ for (int k=0 ; k<3 ; k++) pp (k) = ps (n, k) - ctr (k);
4223+ pp = rot * pp;
4224+
4225+ auto v = basis->getFields (pp (0 ), pp (1 ), pp (2 ));
4226+
41904227 // First 6 fields are density and potential, followed by acceleration
41914228 for (int k=0 ; k<3 ; k++) accel (n, k) += v[6 +k] - basis->pseudo (k);
41924229 }
@@ -4271,11 +4308,18 @@ namespace BasisClasses
42714308
42724309 // Interpolate center
42734310 //
4274- if (coefsA->ctr .size () and coefsB->ctr .size ()) {
4275- newcoef->ctr .resize (3 );
4276- for (int k=0 ; k<3 ; k++)
4277- newcoef->ctr [k] = a * coefsA->ctr [k] + b * coefsB->ctr [k];
4278- }
4311+ newcoef->ctr = a * coefsA->ctr + b * coefsB->ctr ;
4312+
4313+ // Interpolate rotation matrix followed by unitarization
4314+ //
4315+ RowMatrix3d newrot = a * coefsA->rot + b * coefsB->rot ;
4316+
4317+ // Closest unitary matrix in the Frobenius norm sense
4318+ //
4319+ Eigen::BDCSVD<RowMatrix3d> svd
4320+ (newrot, Eigen::ComputeFullU | Eigen::ComputeFullV);
4321+
4322+ newcoef->rot = svd.matrixU () * svd.matrixV ().adjoint ();
42794323
42804324 // Install coefficients
42814325 //
0 commit comments