MayaTransformWriter::MayaTransformWriter(Alembic::AbcGeom::OObject & iParent,
	MDagPath & iDag, Alembic::Util::uint32_t iTimeIndex, const JobArgs & iArgs)
{
	mVerbose = iArgs.verbose;
	mFilterEulerRotations = iArgs.filterEulerRotations;
	mJointOrientOpIndex[0] = mJointOrientOpIndex[1] = mJointOrientOpIndex[2] =
	mRotateOpIndex[0]	  = mRotateOpIndex[1]	  = mRotateOpIndex[2]	  =
	mRotateAxisOpIndex[0]  = mRotateAxisOpIndex[1]  = mRotateAxisOpIndex[2]  = ~size_t(0);

	if (iDag.hasFn(MFn::kJoint))
	{
		MFnIkJoint joint(iDag);
		MString jointName = joint.name();

		mName = util::stripNamespaces(jointName, iArgs.stripNamespace);

		Alembic::AbcGeom::OXform obj(iParent, mName.asChar(),
			iTimeIndex);
		mSchema = obj.getSchema();

		Alembic::Abc::OCompoundProperty cp;
		Alembic::Abc::OCompoundProperty up;
		if (AttributesWriter::hasAnyAttr(joint, iArgs))
		{
			cp = mSchema.getArbGeomParams();
			up = mSchema.getUserProperties();
		}

		mAttrs = AttributesWriterPtr(new AttributesWriter(cp, up, obj, joint,
			iTimeIndex, iArgs));

		if (!iArgs.worldSpace)
		{
			pushTransformStack(joint, iTimeIndex == 0);

			// need to look at inheritsTransform
			MFnDagNode dagNode(iDag);
			MPlug inheritPlug = dagNode.findPlug("inheritsTransform");
			if (!inheritPlug.isNull())
			{
				if (util::getSampledType(inheritPlug) != 0)
					mInheritsPlug = inheritPlug;

				mSample.setInheritsXforms(inheritPlug.asBool());
			}

			// everything is default, don't write anything
			if (mSample.getNumOps() == 0 && mSample.getInheritsXforms())
				return;

			mSchema.set(mSample);

			return;
		}
	}
	else
	{
		MFnTransform trans(iDag);
		MString transName = trans.name();

		mName = util::stripNamespaces(transName, iArgs.stripNamespace);

		Alembic::AbcGeom::OXform obj(iParent, mName.asChar(),
			iTimeIndex);
		mSchema = obj.getSchema();

		Alembic::Abc::OCompoundProperty cp;
		Alembic::Abc::OCompoundProperty up;
		if (AttributesWriter::hasAnyAttr(trans, iArgs))
		{
			cp = mSchema.getArbGeomParams();
			up = mSchema.getUserProperties();
		}

		mAttrs = AttributesWriterPtr(new AttributesWriter(cp, up, obj, trans,
			iTimeIndex, iArgs));

		if (!iArgs.worldSpace)
		{
			pushTransformStack(trans, iTimeIndex == 0);

			// need to look at inheritsTransform
			MFnDagNode dagNode(iDag);
			MPlug inheritPlug = dagNode.findPlug("inheritsTransform");
			if (!inheritPlug.isNull())
			{
				if (util::getSampledType(inheritPlug) != 0)
					mInheritsPlug = inheritPlug;

				mSample.setInheritsXforms(inheritPlug.asBool());
			}


			// everything is default, don't write anything
			if (mSample.getNumOps() == 0 && mSample.getInheritsXforms())
				return;

			mSchema.set(mSample);
			return;
		}
	}

	// if we didn't bail early then we need to add all the transform
	// information at the current node and above

	// copy the dag path because we'll be popping from it
	MDagPath dag(iDag);

	int i;
	int numPaths = dag.length();
	std::vector< MDagPath > dagList;
	for (i = numPaths - 1; i > -1; i--, dag.pop())
	{
		dagList.push_back(dag);

		// inheritsTransform exists on both joints and transforms
		MFnDagNode dagNode(dag);
		MPlug inheritPlug = dagNode.findPlug("inheritsTransform");

		// if inheritsTransform exists and is set to false, then we
		// don't need to worry about ancestor nodes above this one
		if (!inheritPlug.isNull() && !inheritPlug.asBool())
			break;
	}


	std::vector< MDagPath >::iterator iStart = dagList.begin();

	std::vector< MDagPath >::iterator iCur = dagList.end();
	iCur--;

	// now loop backwards over our dagpath list so we push ancestor nodes
	// first, all the way down to the current node
	for (; iCur != iStart; iCur--)
	{
		// only add it to the stack don't write it yet!

		if (iCur->hasFn(MFn::kJoint))
		{
			MFnIkJoint joint(*iCur);
			pushTransformStack(joint, iTimeIndex == 0);
		}
		else
		{
			MFnTransform trans(*iCur);
			pushTransformStack(trans, iTimeIndex == 0);
		}
	}

	// finally add any transform info on the final node and write it
	if (iCur->hasFn(MFn::kJoint))
	{
		MFnIkJoint joint(*iCur);
		pushTransformStack(joint, iTimeIndex == 0);
	}
	else
	{
		MFnTransform trans(*iCur);
		pushTransformStack(trans, iTimeIndex == 0);
	}

	// need to look at inheritsTransform
	MFnDagNode dagNode(iDag);
	MPlug inheritPlug = dagNode.findPlug("inheritsTransform");
	if (!inheritPlug.isNull())
	{
		if (util::getSampledType(inheritPlug) != 0)
			mInheritsPlug = inheritPlug;

		mSample.setInheritsXforms(inheritPlug.asBool());
	}


	// everything is default, don't write anything
	if (mSample.getNumOps() == 0 && mSample.getInheritsXforms())
		return;

	mSchema.set(mSample);

}
Example #2
0
void diamond_dag() {
    DAG dag("test/diamond.dag");
    Engine engine(dag);

    if (!engine.has_ready_task()) {
        myfailure("Did not queue root tasks");
    }
    
    Task *a = engine.next_ready_task();
    if (a->name.compare("A") != 0) {
        myfailure("Queued non root task %s", a->name.c_str());
    }
    
    if (engine.has_ready_task()) {
        myfailure("Queued non-root tasks");
    }
    
    engine.mark_task_finished(a, 0);
    
    if (!engine.has_ready_task()) {
        myfailure("Marking did not release tasks");
    }
    
    Task *bc = engine.next_ready_task();
    if (!engine.has_ready_task()) {
        myfailure("Marking did not release tasks");
    }
    
    Task *cb = engine.next_ready_task();
    if (engine.has_ready_task()) {
        myfailure("Marking released too many tasks");
    }
    
    if (bc->name.compare("B") != 0 && bc->name.compare("C") != 0) {
        myfailure("Wrong task released: %s", bc->name.c_str());
    }
    
    if (cb->name.compare("B") != 0 && cb->name.compare("C") != 0) {
        myfailure("Wrong task released: %s", cb->name.c_str());
    }
    
    engine.mark_task_finished(bc, 0);
    if (engine.has_ready_task()) {
        myfailure("Marking released a task when it shouldn't");
    }
    
    engine.mark_task_finished(cb, 0);
    if (!engine.has_ready_task()) {
        myfailure("Marking all parents did not release task D");
    }
    
    Task *d = engine.next_ready_task();
    if (d->name.compare("D") != 0) {
        myfailure("Not task D");
    }
    
    if (engine.has_ready_task()) {
        myfailure("No more tasks are available");
    }
    
    if (engine.is_finished()) {
        myfailure("DAG is not finished");
    }
    
    engine.mark_task_finished(d, 0);
    
    if (!engine.is_finished()) {
        myfailure("DAG is finished");
    }
}
Example #3
0
int mpidag(int argc, char *argv[]) {
    int numprocs;
    program = argv[0];
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
    
    std::list<char *> flags;
    for (int i=1; i<argc; i++) {
        flags.push_back(argv[i]);
    }
    
    std::string outfile;
    std::string errfile;
    std::string logfile;
    std::list<std::string> args;
    int loglevel = LOG_INFO;
    bool skiprescue = false;
    int max_failures = 0;
    int tries = 1;
    
    while (flags.size() > 0) {
        std::string flag = flags.front();
        if (flag == "-h" || flag == "--help") {
            usage();
            return 0;
        } else if (flag == "-o" || flag == "--stdout") {
            flags.pop_front();
            if (flags.size() == 0) {
                if (rank == 0) {
                    fprintf(stderr, "-o/--stdout requires PATH\n");
                }
                return 1;
            }
            outfile = flags.front();
        } else if (flag == "-e" || flag == "--stderr") {
            flags.pop_front();
            if (flags.size() == 0) {
                if (rank == 0) {
                    fprintf(stderr, "-e/--stderr requires PATH\n");
                }
                return 1;
            }
            errfile = flags.front();
        } else if (flag == "-q" || flag == "--quiet") {
            loglevel -= 1;
        } else if (flag == "-v" || flag == "--verbose") {
            loglevel += 1;
        } else if (flag == "-L" || flag == "--logfile") {
            flags.pop_front();
            if (flags.size() == 0) {
                if (rank == 0) {
                    fprintf(stderr, "-L/--logfile requires PATH\n");
                }
                return 1;
            }
            logfile = flags.front();
        } else if (flag == "-s" || flag == "--skip-rescue") {
            skiprescue = true;
        } else if (flag == "-m" || flag == "--max-failures") {
            flags.pop_front();
            if (flags.size() == 0) {
                if (rank == 0) {
                    fprintf(stderr, "-m/--max-failures requires N\n");
                }
                return 1;
            }
            std::string N = flags.front();
            if (!sscanf(N.c_str(), "%d", &max_failures)) {
                fprintf(stderr, "N for -m/--max-failures is invalid\n");
                return 1;
            }
            if (max_failures < 0) {
                fprintf(stderr, "N for -m/--max-failures must be >= 0\n");
                return 1;
            }
        } else if (flag == "-t" || flag == "--tries") {
            flags.pop_front();
            if (flags.size() == 0) {
                if (rank == 0) {
                    fprintf(stderr, "-t/--tries requires N\n");
                }
                return 1;
            }
            std::string N = flags.front();
            if (!sscanf(N.c_str(), "%d", &tries)) {
                fprintf(stderr, "N for -t/--tries is invalid\n");
                return 1;
            }
            if (tries < 1) {
                fprintf(stderr, "N for -t/--tries must be >= 1\n");
                return 1;
            }
        } else if (flag[0] == '-') {
            if (rank == 0) {
                fprintf(stderr, "Unrecognized argument: %s\n", flag.c_str());
            }
            return 1;
        } else {
            args.push_back(flag);
        }
        flags.pop_front();
    }
    
    if (args.size() == 0) {
        usage();
        return 1;
    }
    
    if (args.size() > 1) {
        fprintf(stderr, "Invalid argument\n");
        return 1;
    }
    
    std::string dagfile = args.front();
    
    if (numprocs < 2) {
        fprintf(stderr, "At least one worker process is required\n");
        return 1;
    }
    
    // Everything is pretty deterministic up until the processes reach
    // this point. Once we get here the different processes can diverge 
    // in their behavior for many reasons (file systems issues, bad nodes,
    // etc.), so be careful how failures are handled after this point
    // and make sure MPI_Abort is called when something bad happens.
    
    char dotrank[25];
    sprintf(dotrank, ".%d", rank);
    
    FILE *log = NULL;
    log_set_level(loglevel);
    if (logfile.size() > 0) {
        logfile += dotrank;
        log = fopen(logfile.c_str(), "w");
        if (log == NULL) {
            failure("Unable to open log file: %s: %s\n", 
                logfile.c_str(), strerror(errno));
        }
        log_set_file(log);
    }
    
    try {
        if (rank == 0) {
            
            // IMPORTANT: The rank 0 process figures out the names
            // of these files so that we don't have 1000 workers all
            // slamming the file system with stat() calls to check if
            // the out/err/rescue files exist. The master will figure
            // it out here, and then broadcast it to the workers when
            // it starts up.
            
            // Determine task stdout file
            if (outfile.size() == 0) {
                outfile = dagfile;
                outfile += ".out";
            }
            next_retry_file(outfile);
            log_debug("Using stdout file: %s", outfile.c_str());
            
            
            // Determine task stderr file
            if (errfile.size() == 0) {
                errfile = dagfile;
                errfile += ".err";
            }
            next_retry_file(errfile);
            log_debug("Using stderr file: %s", errfile.c_str());
            
            
            // Determine old and new rescue files
            std::string rescuebase = dagfile;
            rescuebase += ".rescue";
            std::string oldrescue;
            std::string newrescue = rescuebase;
            int next = next_retry_file(newrescue);
            if (next == 0 || skiprescue) {
                // Either there is no old rescue file, or the
                // user doesnt want to read it.
                oldrescue = "";
            } else {
                char rbuf[5];
                snprintf(rbuf, 5, ".%03d", next-1);
                oldrescue = rescuebase;
                oldrescue += rbuf;
            }
            log_debug("Using old rescue file: %s", oldrescue.c_str());
            log_debug("Using new rescue file: %s", newrescue.c_str());
            
            DAG dag(dagfile, oldrescue);
            Engine engine(dag, newrescue, max_failures, tries);
            
            return Master(engine, dag, outfile, errfile).run();
        } else {
            return Worker().run();
        }
    } catch (...) {
        // Make sure we close the log
        if (log != NULL) {
            fclose(log);
        }
        throw;
    }
    
    if (log != NULL) {
        fclose(log);
    }

    return 0;
}
Example #4
0
int main(int argc, char *argv[]) {
    if(argc != 6 && argc != 7) {
        printf("usage: rrg N n s D seed (id_string)\n");
        return 1;
        }
    time_t t1,t2,tI,tF;
    ITensor U,Dg,P,S;
    Index ei;

    // RRG structure parameters
    const int    N  = atoi(argv[1]); // should be n*(power of 2)
    const int    n  = atoi(argv[2]); // initial blocking size
    int          w  = n;             // block size (scales with m)
    int          ll = 0;             // lambda block index
    int          m  = 0;             // RG scale factor

    // AGSP and subspace parameters
    const double t = 0.3;            // Trotter temperature
    const int    M = 100;            // num Trotter steps
    const int    k = 1;              // power of Trotter op (just use 1)
    const int    s = atoi(argv[3]);  // formal s param
    const int    D = atoi(argv[4]);  // formal D param
    
    // computational settings
    const bool   doI = true; // diag restricted Hamiltonian iteratively?

    // setup random sampling
    std::random_device r;
    const int seed = atoi(argv[5]);
    fprintf(stderr,"seed is %d\n",seed);
    std::mt19937 gen(seed);
    std::uniform_real_distribution<double> udist(0.0,1.0);

    FILE *sxfl,*syfl,*szfl,*gsfl;
    char id[128],sxnm[256],synm[256],sznm[256],gsnm[256];
    if(argc == 6) sprintf(id,"rrg-L%d-s%d-D%d",N,s,D);
    else sprintf(id,"%s",argv[6]);
    strcat(sxnm,id); strcat(sxnm,"-sx.dat");
    strcat(synm,id); strcat(synm,"-sy.dat");
    strcat(sznm,id); strcat(sznm,"-sz.dat");
    strcat(gsnm,id); strcat(gsnm,"-gs.dat");
    sxfl = fopen(sxnm,"a");
    syfl = fopen(synm,"a");
    szfl = fopen(sznm,"a");
    gsfl = fopen(gsnm,"a");

    // initialize Hilbert subspaces for each level m = 0,...,log(N/n)
    vector<SpinHalf> hsps;
    for(int x = n ; x <= N ; x *= 2) hsps.push_back(SpinHalf(x));
    SpinHalf hs = hsps.back();
 
    // generate product basis over m=0 Hilbert space
    auto p = int(pow(2,n));
    vector<MPS> V1;
    for(int i = 0 ; i < p ; ++i) {
        InitState istate(hsps[0],"Dn");
        for(int j = 1 ; j <= n ; ++j)
            if(i/(int)pow(2,j-1)%2) istate.set(j,"Up");
        V1.push_back(MPS(istate));
        }
    MPS bSpaceL(hsps[0]);
    MPS bSpaceR(hsps[0]);
    makeVS(V1,bSpaceL,LEFT);
    makeVS(V1,bSpaceR,RIGHT);

    // Hamiltonian parameters
    const double Gamma = 2.0;
    vector<double> J(2*(N-1));
    fprintf(stdout,"# Hamiltonian terms Jx1,Jy1,Jx2,... (seed=%d)\n",seed);
    for(int i = 0 ; i < N-1 ; ++i) {
        J[2*i+0] = pow(udist(gen),Gamma);
        J[2*i+1] = pow(udist(gen),Gamma);
        fprintf(stdout,"%16.14f,%16.14f",J[2*i],J[2*i+1]);
        if(i != N-2) fprintf(stdout,",");
        }
    fprintf(stdout,"\n");
    fflush(stdout);

    // initialize H for full system and extract block Hamiltonians
    AutoMPO autoH(hs);
    std::stringstream sts;
    auto out = std::cout.rdbuf(sts.rdbuf());
    vector<vector<MPO> > Hs(hsps.size());
    for(int i = 1 ; i < N ; ++i) {
        autoH += (J[2*(i-1)]-J[2*(i-1)+1]),"S+",i,"S+",i+1;
        autoH += (J[2*(i-1)]-J[2*(i-1)+1]),"S-",i,"S-",i+1;
        autoH += (J[2*(i-1)]+J[2*(i-1)+1]),"S+",i,"S-",i+1;
        autoH += (J[2*(i-1)]+J[2*(i-1)+1]),"S-",i,"S+",i+1;
        }
    auto H = toMPO<ITensor>(autoH,{"Exact",true});
    std::cout.rdbuf(out);

    for(auto i : args(hsps)) extractBlocks(autoH,Hs[i],hsps[i]);
    
    vector<MPO> prodSz,prodSx,projSzUp,projSzDn,projSxUp,projSxDn;
    for(auto& it : hsps) { 
        auto curSz = sysOp(it,"Sz",2.0).toMPO(); prodSz.push_back(curSz);
        auto curSx = sysOp(it,"Sx",2.0).toMPO(); prodSx.push_back(curSx);
        auto curSzUp = sysOp(it,"Id").toMPO(); curSzUp.plusEq(curSz); curSzUp /= 2.0;
        auto curSzDn = sysOp(it,"Id").toMPO(); curSzDn.plusEq(-1.0*curSz); curSzDn /= 2.0;
        auto curSxUp = sysOp(it,"Id").toMPO(); curSxUp.plusEq(curSx); curSxUp /= 2.0;
        auto curSxDn = sysOp(it,"Id").toMPO(); curSxDn.plusEq(-1.0*curSx); curSxDn /= 2.0;
        projSzUp.push_back(curSzUp); projSzDn.push_back(curSzDn);
        projSxUp.push_back(curSxUp); projSxDn.push_back(curSxDn);
        }   
 
    // approximate the thermal operator exp(-H/t)^k using Trotter
    // and MPO multiplication; temperature of K is k/t
    time(&tI);
    MPO eH(hs);
    twoLocalTrotter(eH,t,M,autoH);
    auto K = eH;    
    for(int i = 1 ; i < k ; ++i) {
        nmultMPO(eH,K,K,{"Cutoff",eps,"Maxm",MAXBD});
        K.Aref(1) *= 1.0/norm(K.A(1));
        }
    
    // INITIALIZATION: reduce dimension by sampling from initial basis, either
    // bSpaceL or bSpaceR depending on how the merge will work
    vector<MPS> Spre;
    for(ll = 0 ; ll < N/n ; ll++) {
        auto xs = ll % 2 ? 1 : n; // location of dangling Select index
        auto cur = ll % 2 ? bSpaceR : bSpaceL;
        Index si("ext",s,Select);
       
        // return orthonormal basis of evecs
        auto eigs = diagHermitian(-overlapT(cur,Hs[0][ll],cur),P,S,{"Maxm",s});
        cur.Aref(xs) *= P*delta(commonIndex(P,S),si);
        regauge(cur,xs,{"Truncate",false});

        Spre.push_back(cur);
        }
    time(&t2);
    fprintf(stderr,"initialization: %.f s\n",difftime(t2,tI));

    // ITERATION: proceed through RRG hierarchy, increasing the scale m
    vector<MPS> Spost;
    for(m = 0 ; (int)Spre.size() > 1 ; ++m,w*=2) {
        fprintf(stderr,"Level %d (w = %d)\n",m,w);
        auto hs = hsps[m];
        auto DD = D;//max(4,D/(int(log2(N/n)-m)));
        auto thr = 1e-8;
        Spost.clear();

        // EXPAND STEP: for each block, expand dimension of subspace with AGSP operators
        for(ll = 0 ; ll < N/w ; ++ll) {
            MPO A(hs) , Hc = Hs[m][ll];
            MPS pre = Spre[ll] , ret(hs);
            int xs = ll % 2 ? 1 : w;

            // STEP 1: extract filtering operators A from AGSP K
            time(&t1);
            restrictMPO(K,A,w*ll+1,DD,ll%2);
            time(&t2);
            fprintf(stderr,"trunc AGSP: %.f s\n",difftime(t2,t1));

            // STEP 2: expand subspace using the mapping A:pre->ret
            time(&t1);
            ret = applyMPO(A,pre,ll%2,{"Cutoff",eps,"Maxm",MAXBD});
            time(&t2);
            fprintf(stderr,"apply AGSP: %.f s\n",difftime(t2,t1));

            // rotate into principal components of subspace, poxsibly reducing dimension
            // and stabilizing numerics, then store subspace in eigenbasis of block H
            time(&t1); 
            diagHermitian(overlapT(ret,ret),U,Dg,{"Cutoff",thr});
            time(&t2);
            ei = Index("ext",int(commonIndex(Dg,U)),Select);
            Dg.apply(invsqrt);
            ret.Aref(xs) *= dag(U)*Dg*delta(prime(commonIndex(Dg,U)),ei);
            fprintf(stderr,"rotate MPS: %.f s\n",difftime(t2,t1));

            auto eigs = diagHermitian(-overlapT(ret,Hs[m][ll],ret),P,S);
            ret.Aref(xs) *= P*delta(commonIndex(P,S),ei);
            ret.Aref(xs) *= 1.0/sqrt(overlapT(ret,ret).real(ei(1),prime(ei)(1)));
            regauge(ret,xs,{"Cutoff",eps});

            fprintf(stderr,"max m: %d\n",maxM(ret));
            Spost.push_back(ret);
            
            }

        // MERGE/REDUCE STEP: construct tensor subspace, sample to reduce dimension
        Spre.clear();
        for(ll = 0 ; ll < N/w ; ll+=2) {
            auto spL = Spost[ll];                // L subspace
            auto spR = Spost[ll+1];              // R subspace

            // STEP 1: find s lowest eigenpairs of restricted H
            time(&t1);
            auto tpH = tensorProdContract(spL,spR,Hs[m+1][ll/2]);
            tensorProdH<ITensor> resH(tpH);
            resH.diag(s,doI);
            P = resH.eigenvectors();
            time(&t2);
            fprintf(stderr,"diag restricted H: %.f s\n",difftime(t2,t1));

            // STEP 2: tensor viable sets on each side and reduce dimension
            MPS ret(hsps[m+1]);
            time(&t1);
            tensorProduct(spL,spR,ret,P,(ll/2)%2);
            time(&t2);
            fprintf(stderr,"tensor product (ll=%d): %.f s\n",ll,difftime(t2,t1));
 
            Spre.push_back(ret);
            }
        }

    // EXIT: extract two lowest energy candidate states to determine gap
    auto res = Spre[0];
    auto fi = Index("ext",s/2,Select);
    vector<MPS> resSz = {res,res};
    
    // project to Sz sectors of the eigenspace
    diagHermitian(overlapT(res,prodSz[m],res),U,Dg);
    resSz[0].Aref(N) *= U*delta(commonIndex(U,Dg),fi);
    diagHermitian(overlapT(res,-1.0*prodSz[m],res),U,Dg);
    resSz[1].Aref(N) *= U*delta(commonIndex(U,Dg),fi);
   
    vector<MPS> evecs(2);
    for(int i : range(2)) {
        auto fc = resSz[i];
        
        // diagonalize H within the Sz sectors
        auto eigs = diagHermitian(-overlapT(fc,H,fc),P,S);
        fc.Aref(N) *= (P*setElt(commonIndex(P,S)(1)));
        
        fc.orthogonalize({"Cutoff",epx,"Maxm",MAXBD});
        fc.normalize();
        if(i == 0)
            fprintf(stderr,"RRG gs energy: %17.14f\n",overlap(fc,H,fc));
        evecs[i] = fc;
        }
    time(&t2);

    Real vz,vx;
    vz = overlap(evecs[0],prodSz[m],evecs[0]); vx = overlap(evecs[0],prodSx[m],evecs[0]);
    fprintf(stderr,"Vz,vx of 0 is: %17.14f,%17.14f\n",vz,vx);
    vz = overlap(evecs[1],prodSz[m],evecs[1]); vx = overlap(evecs[1],prodSx[m],evecs[1]);
    fprintf(stderr,"Vz,vx of 1 is: %17.14f,%17.14f\n",vz,vx);
    int x1_up = (vx > 0.0 ? 1 : 0);

    evecs[0] = exactApplyMPO(evecs[0],projSzUp[m],{"Cutoff",epx});
    evecs[0] = exactApplyMPO(evecs[0],projSxUp[m],{"Cutoff",epx});
    evecs[1] = exactApplyMPO(evecs[1],projSzDn[m],{"Cutoff",epx});
    evecs[1] = exactApplyMPO(evecs[1],(x1_up?projSxUp[m]:projSxDn[m]),{"Cutoff",epx});
    for(auto& it : evecs) it.normalize();

    fprintf(stderr,"gs candidate energy: %17.14f\nRRG BD ",overlap(evecs[0],H,evecs[0]));
    for(const auto& it : evecs) fprintf(stderr,"%d ",maxM(it));
    fprintf(stderr,"\telapsed: %.f s\n",difftime(t2,tI));

    // CLEANUP: use DMRG to improve discovered evecs
    vector<Real> evals(2),e_prev(2);
    int max_iter = 30 , used_max = 0;
    Real flr = 1e-13 , over_conv = 1e-1 , gap = 1.0 , conv = over_conv*gap , max_conv = 1.0;
    for(int i = 0 ; i < (int)evecs.size() ; ++i) evals[i] = overlap(evecs[i],H,evecs[i]);
    for(int i = 0 ; (i < 2 || conv < max_conv) && i < max_iter ; ++i) {
        e_prev = evals;

        time(&t1);
        evals = dmrgMPO(H,evecs,8,{"Penalty",0.1,"Cutoff",epx});
        time(&t2);
        
        gap = evals[1]-evals[0];

        max_conv = 0.0;
        for(auto& j : range(2))
            if(fabs(e_prev[j]-evals[j]) > max_conv) max_conv = e_prev[j]-evals[j];
        
        fprintf(stderr,"DMRG BD ");
        for(const auto& it : evecs) fprintf(stderr,"%3d ",maxM(it));
        fprintf(stderr,"\tgap: %e\tconv=%9.2e,%9.2e\telapsed: %.f s\n",gap,
            e_prev[0]-evals[0],e_prev[1]-evals[1],difftime(t2,t1));
        conv = max(over_conv*gap,flr);
        if(i == max_iter) used_max = 1;
        }

    for(int i = 0 ; i < (int)evecs.size() ; ++i) {
        vz = overlap(evecs[i],prodSz[m],evecs[i]); vx = overlap(evecs[i],prodSx[m],evecs[i]);
        fprintf(stderr,"Vz,vx of %d is: %12.9f,%12.9f\n",i,vz,vx);
        }

    evecs[0] = exactApplyMPO(evecs[0],projSzUp[m],{"Cutoff",1e-16});
    evecs[0] = exactApplyMPO(evecs[0],projSxUp[m],{"Cutoff",1e-16});
    evecs[1] = exactApplyMPO(evecs[1],projSzDn[m],{"Cutoff",1e-16});
    evecs[1] = exactApplyMPO(evecs[1],(x1_up?projSxUp[m]:projSxDn[m]),{"Cutoff",1e-16});
    for(auto& it : evecs) it.normalize();
    for(auto i : range(evecs.size())) evals[i] = overlap(evecs[i],H,evecs[i]);
    time(&tF);

    auto gsR = evecs[0];
    auto ee = measEE(gsR,N/2);
    gap = evals[1]-evals[0];

    fprintf(stderr,"gs: %17.14f gap: %15.9e ee: %10.8f\n",evals[0],gap,ee);
    fprintf(gsfl,"# GS data (L=%d s=%d D=%d seed=%d time=%.f)\n",N,s,D,seed,difftime(tF,tI));
    if(used_max) fprintf(gsfl,"# WARNING max iterations reached\n");
    fprintf(gsfl,"%17.14f\t%15.9e\t%10.8f\n",evals[0],gap,ee);

    // Compute two-point correlation functions in ground state via usual MPS method
    fprintf(sxfl,"# SxSx corr matrix (L=%d s=%d D=%d seed=%d)\n",N,s,D,seed);
    fprintf(syfl,"# SySy corr matrix (L=%d s=%d D=%d seed=%d)\n",N,s,D,seed);
    fprintf(szfl,"# SzSz corr matrix (L=%d s=%d D=%d seed=%d)\n",N,s,D,seed);
    for(int i = 1 ; i <= N ; ++i) {
        gsR.position(i,{"Cutoff",0.0});
        auto SxA = hs.op("Sx",i); auto SyA = hs.op("Sy",i); auto SzA = hs.op("Sz",i);
        for(int j = 1 ; j <= N ; ++j) {
            if(j <= i) {
                fprintf(sxfl,"%15.12f\t",0.0);
                fprintf(syfl,"%15.12f\t",0.0);
                fprintf(szfl,"%15.12f\t",0.0); 
            } else {
                auto SxB = hs.op("Sx",j); auto SyB = hs.op("Sy",j); auto SzB = hs.op("Sz",j);
                fprintf(sxfl,"%15.12f\t",measOp(gsR,SxA,i,SxB,j));
                fprintf(syfl,"%15.12f\t",measOp(gsR,SyA,i,SyB,j));
                fprintf(szfl,"%15.12f\t",measOp(gsR,SzA,i,SzB,j));
                }
            }
        fprintf(sxfl,"\n");
        fprintf(syfl,"\n");
        fprintf(szfl,"\n");
        }

    fclose(sxfl);
    fclose(syfl);
    fclose(szfl);
    fclose(gsfl);

    return 0;
    
    }
MayaTransformWriter::MayaTransformWriter(double iFrame,
    Alembic::AbcGeom::OObject & iParent, MDagPath & iDag,
    uint32_t iTimeIndex,
    bool iAddWorld, bool iWriteVisibility)
{

    if (iDag.hasFn(MFn::kJoint))
    {
        MFnIkJoint joint(iDag);
        Alembic::AbcGeom::OXform obj(iParent, joint.name().asChar(),
            iTimeIndex);
        mSchema = obj.getSchema();

        Alembic::Abc::OCompoundProperty cp = obj.getProperties();
        mAttrs = AttributesWriterPtr(new AttributesWriter(iFrame, cp, joint,
            iTimeIndex, iWriteVisibility));

        if (!iAddWorld)
        {
            pushTransformStack(iFrame, joint);

            // need to look at inheritsTransform
            MFnDagNode dagNode(iDag);
            MPlug inheritPlug = dagNode.findPlug("inheritsTransform");
            if (!inheritPlug.isNull())
            {
                if (util::getSampledType(inheritPlug) != 0)
                    mInheritsPlug = inheritPlug;

                mSample.setInheritsXforms(inheritPlug.asBool());
            }

            // everything is default, don't write anything
            if (mSample.getNumOps() == 0 && mSample.getInheritsXforms())
                return;

            mSchema.set(mSample);

            return;
        }
    }
    else
    {
        MFnTransform trans(iDag);
        Alembic::AbcGeom::OXform obj(iParent, trans.name().asChar(),
            iTimeIndex);
        mSchema = obj.getSchema();

        Alembic::Abc::OCompoundProperty cp = obj.getProperties();
        mAttrs = AttributesWriterPtr(new AttributesWriter(iFrame, cp, trans,
            iTimeIndex, iWriteVisibility));

        if (!iAddWorld)
        {
            pushTransformStack(iFrame, trans);

            // need to look at inheritsTransform
            MFnDagNode dagNode(iDag);
            MPlug inheritPlug = dagNode.findPlug("inheritsTransform");
            if (!inheritPlug.isNull())
            {
                if (util::getSampledType(inheritPlug) != 0)
                    mInheritsPlug = inheritPlug;

                mSample.setInheritsXforms(inheritPlug.asBool());
            }


            // everything is default, don't write anything
            if (mSample.getNumOps() == 0 && mSample.getInheritsXforms())
                return;

            mSchema.set(mSample);
            return;
        }
    }

    // if we didn't bail early then we need to add all the transform
    // information at the current node and above

    // copy the dag path because we'll be popping from it
    MDagPath dag(iDag);

    int i;
    int numPaths = dag.length();
    std::vector< MDagPath > dagList;
    for (i = numPaths - 1; i > -1; i--, dag.pop())
    {
        dagList.push_back(dag);

        // inheritsTransform exists on both joints and transforms
        MFnDagNode dagNode(dag);
        MPlug inheritPlug = dagNode.findPlug("inheritsTransform");

        // if inheritsTransform exists and is set to false, then we
        // don't need to worry about ancestor nodes above this one
        if (!inheritPlug.isNull() && !inheritPlug.asBool())
            break;
    }


    std::vector< MDagPath >::iterator iStart = dagList.begin();

    std::vector< MDagPath >::iterator iCur = dagList.end();
    iCur--;

    // now loop backwards over our dagpath list so we push ancestor nodes
    // first, all the way down to the current node
    for (; iCur != iStart; iCur--)
    {
        // only add it to the stack don't write it yet!

        if (iCur->hasFn(MFn::kJoint))
        {
            MFnIkJoint joint(*iCur);
            pushTransformStack(iFrame, joint);
        }
        else
        {
            MFnTransform trans(*iCur);
            pushTransformStack(iFrame, trans);
        }
    }

    // finally add any transform info on the final node and write it
    if (iCur->hasFn(MFn::kJoint))
    {
        MFnIkJoint joint(*iCur);
        pushTransformStack(iFrame, joint);
    }
    else
    {
        MFnTransform trans(*iCur);
        pushTransformStack(iFrame, trans);
    }

    // need to look at inheritsTransform
    MFnDagNode dagNode(iDag);
    MPlug inheritPlug = dagNode.findPlug("inheritsTransform");
    if (!inheritPlug.isNull())
    {
        if (util::getSampledType(inheritPlug) != 0)
            mInheritsPlug = inheritPlug;

        mSample.setInheritsXforms(inheritPlug.asBool());
    }


    // everything is default, don't write anything
    if (mSample.getNumOps() == 0 && mSample.getInheritsXforms())
        return;

    mSchema.set(mSample);

}