text:
National Data | "Foreign Labor Contractors" a.k.a. Gangmasters—The New Immigration Paradigm?
Edwin S. Rubenstein
We've all heard stories about Mexican immigrants doing the heavy lifting after Hurricane Katrina. But Chinese immigrants?
That's right—2 to 3 thousand Chinese immigrant workers may soon help rebuild sewers, houses, and water systems in small towns along the Gulf Coast. Local officials claim the Help Wanted sign has been out for months, but big U.S. contractors are simply too busy to work in the affected area.
The Chinese workers won't hop on a plane or take a slow boat from China in hopes of landing a job in New Orleans or Gulfport. They won't enter illegally. If the deal closes they will be hired, en mass, in China by Tangdu International Enterprises—a Chinese labor contractor. When they arrive, they'll work for two large Chinese companies—Beijing Construction Engineering Co., Ltd., and Beijing Urban Construction—and smaller local partners.
To add insult to injury, these companies say they'll use Chinese building materials in order to avoid the higher-priced, but sturdier, American products.
What does this portend for structural integrity in a future Katrina? Or, more importantly, for the integrity of (what's left) of our immigration controls?
For this anecdote is of more than local interest. It exemplifies a new model of immigration.
Traditionally immigrant workers negotiated directly with their U.S. employers. In the new paradigm, labor contractors like Tangdu hire immigrant workers for many U.S. employers simultaneously. On VDARE.COM, these employers have been called "gangmasters".
One of the largest contractors is an outfit called Global Horizons. Its website describes it as
"…the first company to establish a new and improved labor-recruiting, labor providing business model to meet the temporary and permanent needs of employers worldwide."
"Recruiting quality workers from diverse places like Thailand, India, Nepal, Israel, as well as Eastern and Western Europe, Global Horizons brings these workers to any economy where domestic labor is in short supply because of the "economic evolution" occurring in that particular country. This, of course, includes the United States of America."
Global Horizons was founded in 1989 by an Israeli, and is currently headquartered in Los Angeles. At any one time it has 3 to 4 thousand farm workers under contract in up to 28 states.
Contract labor is increasingly the norm in agriculture. In 2002 43% of California's farm workers were supplied by third-party contractors, the rest were hired directly by farmers. In 1983 only 28% were hired by contractors. [Farms Increasingly Rely on Subcontracted Farmworkers, Petoskey News-Review, AP, July 14, 2006.]
Farm workers are brought under the H-2A visa program for seasonal agricultural workers. To earn a visa, employers must show that they've tried to recruit US workers first, and provide free, DOL-approved housing for all temporary hires.
But western farmers do not like the H-2A program. They say it is too inflexible for "perishable western agriculture" because it requires farmers to certify their need for workers 60 days before hiring them. The housing requirement is also regarded as onerous.
Enter the labor contractor.
In 2004 Global Horizons brought in hundreds of H-2As from Thailand to work in Washington State's Yakima valley. The workers were housed in overcrowded motel rooms that violated local health regulations for human habitation. There were no kitchens or laundry facilities. Global Horizon's workers were paid less than the wage for which they were contracted.
Washington State fined Global Horizons for violating labor laws, and in 2005 forced the firm to pay complete financial restitution to workers and the state totaling $230,000. The employers didn't pay the fine—Global Horizons did.
Similarly, if Global Horizons had brought in illegal aliens instead of H-2As, they would have absorbed the fines that would otherwise have been levied on the employers that hired them.
There are other advantages of hiring via contractors. Contractors enable employers, in effect, to outsource their HR departments, reducing the expenses involved in vetting new employees and applying for their visas. Some contractors even provide equipment for their workers—a big savings for employers.
But the big draw is the avoidance of legal liability. In the words of U.C.-Davis economist Phillip Martin, labor contractors act as "…..'risk absorbers,' absorbing fines that could otherwise be levied on the farms where the workers were employed in the event of immigration enforcement."
In theory, the workers can also benefit. They're more likely to have stable employment with a large contractor. The United Farm Workers supports the H-2A visa program—claiming that H-2A status makes farm workers more likely to join unions and press for wage hikes.
But in a global economy, these gains are elusive at best. Economic differences among countries are widening—encouraging migration from low to high wage countries.
In 1975, for example, the per capita income gap between rich countries (defined as those with $9,300 or more per person per year) versus poor countries (below $750 per year) was 41 to 1; by 2000 this gap had grown to 66 to 1. [Phillip Martin, "Managing Labor Migration: Professionals, Guest Workers, and Recruiters," United Nations Expert Group Meeting on International Migration and Development, July 6-8, 2005.]
International contractors can round up crews from all over the world, and then negotiate with U.S. employers on behalf of the entire crew. There inevitably is a race to the bottom, with Mexicans (per capita GDP $10,000 per year) displacing Americans ($42,000), and Chinese ($6,800) displacing Mexicans. Even Chinese income levels would look good to an Indian worker ($3,300) or a Bangladeshi ($2,100).
The wider the income gap between the native and immigrant workers, the more profitable labor contracting becomes.
No one knows this better than the federal officials who administer the H-2A visa program.
In fact, several ex-administrators of the H-2A visa program have left the Department of Labor to open their own labor brokerages. They became labor contractors—applying to their former colleagues for visas.
Surprise, surprise: the number of jobs certified as requiring H-2A workers rose sharply after they left. Not to mention the fees collected by the new labor contractors.
We don't allow military brass to leave the Pentagon one day and work for defense contractors the next. Shouldn't we have the same safeguards for officials who administer our immigration laws?
This is moral hazard, pure and simple. Yet it's apparently all legal—as are the immigrants this corrupt system brings into the country.
Legal, that is, until Congress wakes up. Or is woken up.
Edwin S. Rubenstein (email him) is President of ESR Research Economic Consultants in Indianapolis.

redpajama_set_name: RedPajamaCommonCrawl


Why choose a Limited Liability Company?
LLC's provide limited liability protection to their owners (called members). Typically, owners are not personally responsible for business debts and liabilities of the company so creditors cannot pursue owners' personal assets to pay business debts. This type of company can not issue shares to create capital for the business nor has the ability to elect a board of directors.
Limited Personal Liability - Members of an LLC have very limited liability for the debts, obligations and actions of their company, meaning they can only be held to them if they have signed a personal guarantee.
Pass Through Taxation - Although LLCs exist as separate entities, their earnings are not taxed at a corporate level. Any income or loss is reported on members' personal tax returns. This helps them avoid the issue of double taxation faced by C corporations, which have earnings taxed both at the corporate level and on the personal tax returns of their owners.
Ownership Flexibility - Forming an LLC gives the parties involved a flexible ownership structure that doesn't set limitations on who can be involved. The company can have any number of members, which can include individuals, corporations, foreign entities or even other LLCs.
Disproportionate Profit Distribution - LLCs also allow members to be flexible in how they split up the company's earnings. This means that profits and losses do not need to be given out according to how much of the company each member owns.
Relaxed Reporting Requirements - Starting an LLC allows members to avoid many of the corporate formalities of other business entities. While LLCs do have some reporting requirements, they have less annual paperwork and aren't required to keep minutes or hold annual meetings.
Unattractive to Outside Investors - While LLCs are an attractive format for many types of small businesses, they are not designed for companies that expect to grow significantly or work with venture capital investors. LLCs that do decide they want to pursue outside investment may want to convert their businesses into C corporations.
Differing Treatment Across State Lines- Because many states have different regulations surrounding LLCs, companies that operate in multiple states may not get consistent treatment.
Limited Life - The existence of LLCs is not necessarily perpetual, and some state laws require that they be dissolved after a specific length of time (generally 30 to 40 years). The company technically dissolves when one of its members leaves.
Unavailable for Some Businesses - Certain types of businesses, such as banks and insurance companies, are not allowed to form LLCs.


Doctors are failing to spot dangerous breech pregnancies because physical examinations are not sensitive enough, experts warned today.
A study found that around a third of breech positions could be missed because a routine examination merely involves feeling the stomach.
Australian researchers studied 1,633 women at 35 to 37 weeks gestation who attended an obstetric hospital in Sydney.
Each woman underwent a physical examination to assess the position of their baby, and then had an ultrasound scan to confirm the diagnosis.
The researchers found that the physical examination detected just 70% of the breech positions.
Detection rates were also lower among women who were overweight or obese, the study, published in the British Medical Journal, found.
During the late stages of pregnancy, babies move into a head-down position ready for birth but some babies fail to move correctly into position, making normal vaginal delivery much more difficult.
Complications and the chance of the child dying are higher when breech birth is detected following the onset of labour, studies have shown.
Many women carrying breech babies are offered a caesarean section after a study published in 2000 showed that the risk of death or serious harm to child was more than three times lower in those who had the operation.
The researchers behind the Australian study said that in a general maternity population of 1,000 women, the physical examination alone would identify 101 women as having a breech baby.
That, however, would only be a correct diagnosis for 56 of the women and 24 women having a breech baby would be missed altogether, the authors said.
They argued that routine ultrasound scans would improve detection rates and suggested such scans should be introduced for overweight or obese women, but noted that this would increase costs.


text:
Will he or won't he? So the Browns have assigned o...
<!--[if gte mso 9]> Normal.dotm 0 0 1 647 3...
<!--[if gte mso 9]> Normal.dotm 0 0 1 1151 ...
Will he or won't he?
So the Browns have assigned only 15 players with first-round grades in next month's college football draft. Because they had a much-better-than-expected record last season, they were scheduled to draft 17th in the opening round.
But since they sent that selection to the New York Giants in the Odell Beckham Jr. blockbuster deal, they now have to wait until midway through the second round to dip into the college lottery.
Meaning, of course, that even if they had held on to that 17th pick, they probably wouldn't have used it because all of those 15 would theoretically be gone. A convenient excuse to be only spectators on opening night of the three-day extravaganza.
It's also an interesting way of rationalizing shipping that pick to the Giants. It's like saying, "We had the 17th pick and awarded first-round grades to only 15 prospects, so why not deal it because it would have been second-round talent, anyway?"
Logic suggests there is no way the Browns will participate in the opening round, watching instead as the top players fall, giving the club's fans, who are no doubt sick and tired of watching their cub drafting so high on an annual basis, the night off.
Unless, that is, General Manager John Dorsey, whose star has now risen to celestial heights, somehow finds a way to move up to grab one of those 15 prospects who falls unexpectedly into his crosshairs.
It won't take much. The rhythm of a draft is such that it can be upset by just one major surprise in the top five. One shocker can create a domino effect and knock everyone else down.
The only problem there is Dorsey, who loves to deal, does not own enough trade capital with his personnel. After unloading Kevin Zeitler and Jabrill Peppers to the Giants, he has little to work with beyond the growing array of core players he won't deal.
The only weapon he can wield is next year's first-round pick. The likelihood of that eventuating, however, ranks somewhere between "no way" and "is he crazy?" Or does it?
Dorsey's expected non-participation the first night is the price he has paid to mold the Cleveland offense into one of the strongest and scariest in the National Football League. In other words, it was well worth it.
No sense is pushing the envelope unless someone he has totally fallen in love with tumbles and pushes him to search for a trade partner. Considering his reputation as a risk taker, though, it wouldn't be surprising to see him swing into action.
It potentially gives the expression "stay tuned" an entirely different meaning
In the midst of the glee and euphoria surrounding the trade that set the National Football League aflame a few days comes a caveat with regard to the immediate future of the Browns.
There is no question General Manager John Dorsey has cobbled together a roster in just 15 months that qualifies as one of the best in the NFL. The talent quotient is right there with Kansas City, New England and the Los Angels Rams.
The big question is whether the coaching staff under rookie head coach Freddie Kitchens is seasoned enough to handle this vast array of talent, the likes of which hasn't graced the Cleveland football landscape in a very long time.
Dorsey believes so. "From a planning standpoint, you want to surround a first-year head coach with quality coaches at all levels," he told the Cleveland media last week. "I think we've done that. Surround him with a strong coaching staff."
Kitchens' star has risen so rapidly, so majestically, the fact he has never been the lead whistle of a football team on any level has been shunted to the background in light of all the personnel moves.
There is no question whatsoever the new boss of the locker room has the chops to handle an offense. That was more than evident in the second half of last season when he transformed the Cleveland offense into one of the league's most dangerous.
But there is more, a lot more, to being a head coach than shepherding just one side of the football. It is an entirely different world because he now has the ears of the entire team. He is the man who sets the tone for everything going forward.
Initial observations from listening to Kitchens indicate he will be a players' coach. Instead of separating himself from the players in a somewhat aloof manner, he genuinely cares about them on a personal basis.
The NFL head coaching landscape is dotted with coaches who prefer their relationships with the players to be strictly on a coach-player plane, a business basis. Kitchens is too down home to bend in that direction.
I get the impression he believes his success will be determined on how close he gets to the players, planting seeds in an effort to get them to play that much harder for him because they really want to.
As a neophyte to the head coaching ranks, he has to straddle a fine line as he tries to please his many bosses in the Ivory Tower and, at the same time, maintain a close relationship with his team.
He has to identify and then put out fires that are bound to occasionally erupt in the locker room. With strong and somewhat unpredictable personalities like Baker Mayfield, Jarvis Landry and Odell Beckham Jr. in that room, anything is possible.
That's not to say trouble will always be lurking. But part of Kitchens' job entails sniffing out the fire before it becomes a blaze and snuffing it out. Establishing harmony in a room of 53 players is quintessential to the performance of the end product.
Kitchens obviously has the ringing endorsement of his general manager. "This head coach is very direct, very honest," Dorsey said. "He's going to tell it like it is. . . . He will hold players accountable. He'll let players express themselves as he should do."
That includes Beckman, whose unpredictability in New York greased the slide that saw him dealt to the Browns. "(Kitchens) will tell Odell like it is," the GM said. ". . . We really like Odell. He's passionate, He's competitive. He wants to be great. You can't have enough of those guys. . . . We're thrilled to have him."
There is also no question Mayfield loves his new head coach. He has made that clear since the appointment in January. It will be interesting, maybe even fascinating, to see how much of an influence he can be on the rest of the offense in that regard.
At the tail end of last season, members of the offensive line practically rhapsodized in their praise of the rookie quarterback. The trickle down effect was astounding. That bears watching in 2019.
This is a football team that is loaded with talent, especially on offense. You can bet Dorsey, along with owners Dee and Jimmy Haslam III, and the fans expect positive results almost immediately.
All this is new to Kitchens, who will matriculate through his rookie season as a head coach under as much, maybe even more, pressure to succeed than any Browns head coach since, well, since Bill Belichick took over back in 1991. How he handles it will be a determining factor on how successful the 2019 Browns are.
Dealing Duke a mistake
Now that the Browns know they won't have the services of running back Kareem Hunt until the second half of the 2019 season, it's time for Browns General Manager John Dorsey to stop shopping Duke Johnson Jr.
There is no logical reason to continue to solicit any kind of activity that would land the versatile running back/wide receiver on the roster of another National Football League team.
Besides, there is no guarantee Hunt, who received an eight-game suspension by the NFL Friday and will be a restricted free agent at the end of this season, will return to the Browns for the 2020 season.
The Browns rescued the Willoughby native after the Kansas City Chiefs cut him late last season following violations of the league's personal conduct policy. He obviously is grateful, the Browns signed him, but in the business world, that goes just so far.
Unless Dorsey, who drafted Hunt as the Chiefs' general manager, can extract a promise from Hunt that he will sign a long-term contract with Cleveland after this season, it makes no sense to deal Johnson now. That's not going to happen.
It's difficult to understand why Dorsey is thinking of dealing Johnson when he says, "Duke Johnson is a really good player. He's a very valuable asset on this team." And "you can never have enough talent on a team."
Now that Odell Beckham Jr. is aboard, that virtually eliminates Johnson from being part of the pass offense. All of which pigeonholes him at running back and he is a decided No. 3 behind Nick Chubb and Hunt, once he returns from suspension.
Now Dorsey is clearly gambling – so what else is new? – that Hunt will see the light and remain with the team that tossed him a lifeline. Then again, there is a chance he just might say adios next year when a team looking for a stud running back with the résumé he owns and offers him more money than the Browns are willing to match.
Also take into consideration Hunt, once he returns, will share reps with Chubb, a situation he might not like considering he was the man in Kansas City and rarely missed plays.
That's part of the conundrum. There are too many possibilities of losing Hunt next year for Dorsey with regard to dealing Johnson. Unless, of course, he genuinely does not believe Johnson is a fit with this team.
Unfortunately, the last two Browns coaching staffs have not maximized his talents. So if Dorsey insists on looking for a trade partner, a team like the New England Patriots and offensive coordinator Josh McDaniels would be a perfect fit.
About the best the Cleveland GM can hope for in return is a fifth-round draft pick or a marginal player best suited for special teams.
The future has arrived
At the recent National Football League Scouting Combine in Indianapolis, the media asked Browns General Manager John Dorsey about his team and what the future looked like.
The question, prompted by the club's surprisingly good showing last season, drew the following answer: "I don't think we're a team yet to go for it. We have a young, talented team. Let's build a foundation here. Let's build a team of substance, OK?"
Now maybe Dorsey was being overly modest about what the Browns accomplished in his first full season as GM. Then again, maybe he knew what the immediate future held and was merely pretending.
After stunning the NFL – and the entire sports world, for that matter – by trading for New York Giants superstar wide receiver Odell Beckham Jr, Tuesday, it turned out the audacious Dorsey clearly was playing his cards close to the vest.
When the blockbuster news arrived shortly before 8 o'clock Tuesday night that the Browns had shipped their first-round pick and the lower of two third-round choices in next month's college draft and safety Jabrill Peppers to the Giants for the peerless Beckham, it shook the NFL Universe to its core.
The future is clearly bright now in Berea and Dorsey, even more clearly, is as all in as a poker player sitting with a straight flush and equally straight face.
His aim is higher, a whole lot higher, than the AFC North championship, which seemed like an achievement just a few short months ago. The championship thoughts now coursing through his mind are much closer to the Super Bowl.
All of which makes the almost-miraculous transformation of this franchise in the last 15 months, or since Dorsey took charge, as remarkable as any in recent NFL memory.
This franchise was setting numerous records for futility as recently as a couple of years ago. They became only the second team in league history to lose all 16 games in one season (2017) and won only once in 32 games in consecutive campaigns.
The Cleveland Browns were an embarrassment to the league, wandering aimlessly. Finishing in the basement was an annual event. Fans jumped off the bandwagon in droves.
Then along came Dorsey, who keeps topping himself, with a simple objective. Change the culture. He methodically dismantled half the roster he inherited and went to work shaping the immediate future in his image.
And now comes the piece de résistance. Landing one of the genuine superstars of the NFL at a time when doing so was merely a pipe dream, a thought bubble that kept exploding because it was not doable.
After signing him to a new five-year, $98.5 million contract last summer the Giants maintained they would not trade Beckham, but would certainly listen to offers. Giants GM Dave Gettleman repeatedly told the media, as recently as the Scouting Combine, "We didn't sign Odell to trade him, OK?"
As much as Browns Nation dreamed of such a deal, they realistically couldn't help but think it had no chance of happening.
Until it did. And it instantaneously labels the Browns relevant in a spectacular way.
Helping Dorsey pry Beckham loose might have been a story floating around New York that Beckham was not a favorite of Giants coach Pat Shurmur, who would not be unhappy to see him leave. Gettleman ostensibly had two choices: Trade Beckman or fire his coach.
Dorsey and Gettleman, who successfully negotiated the Kevin Zeitler-Olivier Vernon trade just a few days ago, probably expanded their discussions to Beckham before agreeing on the second swap.
To make matters a little easier logistically, the clubs have agreed to combine the two deals, making it Zeitler, Peppers, a one and a three for Beckham and Vernon. That's outright thievery in broad daylight either way.
I was of the belief it would cost at least a pair of ones, a two and a higher profile player than Peppers, who has not lived up to expectations, although he did appear to put together a much stronger second half last season after being totally misused as a rookie.
The King's ransom thought to be the key to dislodging Beckham from the Giants' roster turned out to be a pawn's ransom by comparison as Christmas and New Year's arrived in Cleveland 10 months early.
The gravitas Beckham brings to Cleveland, added to that of Baker Mayfield, now places the Browns in the upper echelon of relevance from a media standpoint. Networks will scramble to land as many nationally televised Browns games as they can.
With the likes of Beckham, his college buddy Jarvis Landry, Mayfield, Nick Chubb, the distinct possibility of Kareem Hunt, emerging tight end David Njoku and a defense that ultimately could be the most improved in the league this season, Browns fans should have no problem getting used to the national spotlight.
The acrobatic and highly entertaining Beckham, who has averaged 93 yards a game and scored 44 touchdowns in five seasons, legitimizes a Cleveland offense that flirted with being one of the most dangerous in the league in the second half of last season. Some national media observers are calling the Browns "scary good."
Keeping the mercurial Beckham happy in his new environment should not be a problem, Besides rejoining his former Louisiana State teammate Landry, he also will be coached by Adam Henry, their position coach at LSU.
The domino effect on offense should be felt almost immediately and serve as a supreme challenge to the creative minds of new head coach Freddie Kitchens and offensive coordinator Todd Monken.
The mind boggles at what these guys can do with the talents of Mayfield, Beckham, Landry, Antonio Callaway, Njoku, Chubb, Hunt, etc. There is so much talent on that side of the football now, the only problem might be keeping everyone engaged and happy.
The deals have also had an immediate impact on betting odds for this season. The team that annually scraped the bottom of the NFL for nearly two decades went from 25-1 to 14-1 to win the next Super Bowl and from 12-1 to 7-1, behind only New England and Kansas City, to win the AFC championship.
Social media exploded with the news as prominent athletes around the sports world chimed in. Former Cavaliers great LeBron James, a Dallas Cowboys fan, tweeted: "OH!!!! S*#% just got REAL!!" Might he be thinking of switching allegiances?
"Movement." was all Mayfield needed to tweet. Added Dez Bryant, "The whole New York Giants fan base just switched to Cleveland . . . SMH".
The seismic aftershocks of this deal will be felt for quite a while, dominating the headlines before simmering down and then firing up again as teams prepare for the upcoming season with OTAs, minicamps and then summer camps.
The Browns and their fans had better get used go the national attention this team is certain to attract. The whole new culture in Berea also will take some getting used to after all these years of futility and frustration and being ignored. It's pretty safe to say now the Factory of Sadness that sits by the lakefront will take on a brand new name.
At the same time, I cannot adequately describe how utterly strange it seems to be typing Super Bowl and Cleveland Browns in the same sentence. It's a strange and somewhat surreal feeling.
And that rapidly shrinking bandwagon is loading up again and should reach capacity, if there is such a thing considering the international reach of Browns Nation, well before the start of the 2019 season as visions of a return to the glory days of this once-proud franchise dance around.
Fans who have stuck around and been patient through the last two decades despite all the losing will now be rewarded for their patience and loyalty with the kind of football team they expected when the NFL allowed it to return in 1999 after an undeserved three-year absence.
Bottom line: OBJ in Cleveland is one of the most joyous OMG moments in not just Cleveland Browns history, but Cleveland sports history, ranking right up there with the LeBron James era. Two transcendent, generational athletes performing for the great sports fans of Cleveland.
Posted by Rich Passan at 12:03 PM 7 comments:
Defensive line sports new look
John Dorsey, the mad scientist of Berea, emerged from his underground laboratory Tuesday with yet another piece of the puzzle along the Browns' defensive line.
In agreeing with defensive tackle Sheldon Richardson on a three-year, $39 million contract, which will be announced officially Wednesday, Dorsey all but assured the 2019 revamped defensive line will look nothing like the one that performed in 2018, especially from a quality standpoint.
With newly-acquired Olivier Vernon partnering with Myles Garrett on the edges and Richardson lining up next to Larry Ogunjobi, journeys deep into to the offensive backfields of opponents should ostensibly become much more frequent and productive.
The question, however, is what Sheldon Richardson have the Browns signed? The one who played defensive end so well for four seasons with the New York Jets? Or the one whose production fell off after being switched to tackle the last two seasons in Seattle and Minnesota?
Does he still have the skills that earned him defensive Rookie-of-the-Year honors in the National Football League? Or have they eroded to the point where he has become an NFL vagabond, playing with his fourth team in four years?
Dorsey is clearly gambling (shocking, I know) that Richardson, same age as Vernon at 28, sill has plenty left and playing with a team clearly on the rise will serve as motivation. Theoretically, both men are in the prime of their careers. Playing with Garrett certainly won't hurt.
The big problem on defense last season was the inability – with Garrett the lone exception – to make life uncomfortable for opposing quarterbacks. Add the inability to stop the run game and fixing the defensive trench all added up and became priority No. 1.
There is no reason to believe Dorsey will stop there. The college draft is loaded this season with quality defensive linemen and it would not surprise to see the Cleveland general manager attempt to strengthen the depth there.
Enough skill players taken early in the draft should push a high quality defensive lineman or two down to the Browns' slot at No. 17. Unless, of course, Dorsey feels the need to move up and grab someone he has identified as a must-get.
The two latest moves, in addition to the continuing growth of second-year hybrid linebacker Genard Avery, relegate second-year disappointment Trevon Coley to a situational role inside and seriously jeopardize Emmanuel Ogbah's stay in Cleveland.
It will also give new defensive coordinator Steve Wilks and his staff a chance to unlock the mystery of why Chad Thomas, a third-round draft pick last year, all but disappeared during the season and contributed less than zero.
The 67th overall selection in the lottery should not become a cipher in the grand scheme of things with a professional football team. His team biography says he is "a working music producer when not playing football and produced tracks for (several) recording artists." The Browns need him to produce . . . on a football field.
One less concern on offense: Breshad Perriman somewhat surprisingly signed a one-year, $4 million contract Tuesday, 24 hours before his contract would have expired.
The former first-round draft choice by Baltimore, whose career took off with the Browns last season after three disappointing seasons with the Ravens, was rumored to be using last season's success as a reason to test free agency.
It is being labeled a prove-it signing, as in prove last season – the speedy wide receiver caught 16 passes for 340 yards and a pair of touchdowns in 10 games – was no fluke and further success this season would act as a bridge to a much more lucrative future contract.
It is widely believed Perriman had become one of quarterback Baker Mayfield's favorite receivers, averaging 21.3 yards a reception, but he was targeted just 25 times in his 10 games.
The Perriman signing might also influence Rashard Higgins, more of a possession receiver whose production increased markedly in his third year last season, to re-up with the club.
There is no question the contributions of Perriman and Higgins were significant as the Browns displayed one of the NFL's most dangerous offenses in the second half of last season.
Together with veteran Jarvis Landry and rookie Antonio Callaway, what once was a club weakness at wide receiver has arguably become a strength. And if Dorsey somehow manages to land free agent Tyrell Williams, Mayfield becomes that much more dangerous.
Let's start with the fresh stuff and work back to recent events that have aged the last few weeks.
John Dorsey arrived in Cleveland about 16 months ago with the reputation of getting things done in a hurry.
It took him less than one season to overhaul the roster of the National Football League's most moribund franchise and emerge with what can arguably be called the most surprising record in the league last season.
The fact that he labeled it unsatisfactory – it all depends on your perspective – was a clear signal it will not be any different this season.
Sending guard Kevin Zeitler, the club's best offensive lineman the last two seasons and one of the best in the NFL overall, to the New York Giants for defensive end Olivier Vernon a few days ago proves it.
Shipping a high quality offensive lineman in his prime (he's only 29) takes plenty of nerve and a gambling gene that constantly needs to be scratched. Never mind that Vernon is high quality, too, and fills a need.
What Dorsey has done in the process is weaken a unit that struggled with the ground game last season. It seems as though that was the only way he could justify taking Austin Corbett at the top of round two in last season's college draft.
Corbett, who played just about every minute of the 2018 exhibition season and sat out just about all of the regular season, is not Zeitler. At least not yet. It is unfair to draw that comparison, and yet here we are.
With problems at left tackle – Greg Robinson struggled in the run game and excelled at protecting Baker Mayfield when he wasn't holding the opponent – and now right guard, Dorsey is rolling the dice on a unit vital to the success on that side of the ball.
It is entirely possible the GM will go shopping in this year's college lottery to help that unit in an effort to sustain the success it enjoyed in the second half of last season. Because right now, the quality quotient is well below last season's with Zeitler's absence.
Vernon, on the other hand, definitely fills a need and checks off one of areas that plagued the club last season – the pass rush. When one man (Myles Garrett) has 13½ of the team's 37 sacks, you've got a problem.
Vernon, who labored last season playing in a 3-4 scheme as an outside linebacker with the Giants, returns to end in the 4-3 look of new defensive coordinator Steve Wilks and should finally take some of the pressure off Garrett.
Emmanuel Ogbah certainly hasn't the last two seasons and most likely will see more time inside if he makes the final cut or survives long enough to make it to summer camp.
This could very well turn out to be one of those unusual trades that helps both teams. Zeitler will fit in nicely with the Giants, whose offensive line has struggled the last couple of seasons. Vernon will help the sack total rise. It all depends on Corbett.
Rampant speculation that Duke Johnson Jr. might not be a member of the Browns this year is troubling. Rumors that refuse to go away suggest numerous NFL clubs would love to have the running back on their roster.
Why in the world would Dorsey risk losing one of the best playmakers on the club by trading him? He says he isn't trying to do that, but would not refuse to take calls from other clubs with that in mind. In other words, Johnson is not untouchable.
Dorsey dances gingerly down that two-way street with a player who would look great on a team that knows how to best utilize this talents. Something the Browns have had difficulty with.
Is Johnson a running back? Or is he a receiver? He's both. He's the kind of player you want to own the football because he makes good things happen with his feet. Get him the ball and watch him make plays.
If new head coach Freddie Kitchens is such an offensive genius, it shouldn't be that difficult for him to scheme plays that best suit Johnson's talents. That talent has been wasted far too long in Cleveland.
JAMIE COLLINS
Can't blame Dorsey for cutting Collins, whose inconsistent play last season contributed to the disappointing defensive showing last season. It wasn't just him, to be sure, but the large contract that kept him in Cleveland strangled his chances of remaining.
Sashi Brown vastly overpaid Collins after he played very well for a half season after joining the team in a trade midway through the 2016 season. There was no way he was going to renegotiate the four-year, $50 million contract.
Keeping him did not justify the money he was set to make considering how far his game had fallen off. "There were some inconsistencies," Dorsey said following Collins' release. "He may have been nicked. All I know is he is a very talented football player. You can't have enough of those guys on your team."
A classic case of damning with faint praise.
Free agency lurks around the corner with the first day of the 2019 league year set to begin at 4 p.m. on Wednesday shortly after all 2018 player contracts expire. Contract negotiations with free agents are permitted on Monday with the trading period beginning Wednesday at 4.
The annual college draft will be conducted April 25-27 in Nashville. The Browns, barring unforeseen maneuvering by Dorsey, are scheduled to select 17th in the opening round with needs at defensive tackle, offensive line, linebacker (inside and outside), wide receiver and the secondary (in that order).
Posted by Rich Passan at 5:16 PM 2 comments:


Product Description A range of hardtails with 27.5" (Big Seven) and 29" (Big Nine) whee..
Product Description A range of hardtails with 27.5" (Big Seven) and 29" (Big Nine) wheels..
Product Description Aluminium hardtails are our bread and butter, this bomb proof 6061 series..
Product Description Aluminium hardtails are our bread and butter, this bomb proof 6061 series d..
Product Description New Speed frame with lower stand over height and many design cues from ..
Product Description For 2019, carbon and premium aluminium frames are 29" wheel only, ref..
Product Description For 2019, carbon and premium aluminium frames are 29" wheel only, refle..
Product Description For 2019, carbon and premium aluminium frames are 29" wheel only, reflect..
Product Description For 2019, carbon and premium aluminium frames are 29" wheel only, reflectin..
Frame 6061 Double Butted And Technoformed Aluminium Frame. Tapered Headtube (With Re..
Product Description A range of hardtails with 27.5" (Big Seven) and 29" (Big Nine) wheels. Frame ..
Product Description Aluminium hardtails are our bread and butter, this bomb proof 6061 seri..
Product Description The Merida Big Seven 300 is a classic hardtail mountain bike that features a ..
Product Description A classic hardtail mountain bike, the Merida Big Seven 40-D rolls on 27.5" wh..
Product Description A classic hardtail mountain bike, the Merida Big Seven 80-D rolls on 27.5" wh..
Product Description As close as you can get to full suspension thrills on a hardtail, a lon..
Product Description As close as you can get to full suspension thrills on a hardtail, a long ..
Product Description As close as you can get to full suspension thrills on a hardtail, a long re..
Product Description A perfect blend of comfort, enjoyment and all-round practicality suitable..
Product Description A perfect blend of comfort, enjoyment and all-round practicality suitab..
Product Description Fast efficient and comfortable on road, track and trail. The Merida Crossway ..
Product Description A perfect blend of comfort, enjoyment and all-round practicality suitable f..
Frame 6061 Double butted and technoformed aluminium frame. Equipped with mounts for ..
Product Description Quick, comfortable and confident, on road, track and trail. The Merida Crossw..
Product Description A faster, more contemporary version of the Crossway, visually the key dif..
The Crossway Urban is your perfect commuting comrade. With its rigid fork to reduce weight and nutte..
Product Description A faster, more contemporary version of the Crossway, visually the key d..
Product Description A faster, more contemporary version of the Crossway, visually the key..
One of our top sellers, highly finished lightweight 6061 Double butted and technoformed aluminium fr..
Product Description A faster, more contemporary version of the Crossway, visually the k..
Product Description Versatile cycling performance in the urban jungle. The Merida Crossway Urban ..
Product Description A faster, more contemporary version of the Crossway, visually the key diffe..
Product Description When trying to describe an entry level cyclo cross model it is tricky t..


Designed and constructed specifically for the ladies of Baylor, we're positive that our college apparel and accessories will make you look fantastic. Barefoot Campus Outfitter harnessed the unmatched school spirit and unrelenting style of the Baylor women and used that to make our women's line of campus apparel. Whether you're looking for a college t-shirt to wear to the game or a new hat to shade your face from the Texas sun, we're sure that you'll find something that's both super chic and comfortable. Made for college students, all of our gear is made as affordable as possible so you won't have to fret about spending.


text:
from __future__ import unicode_literals
from __future__ import division

"""
Evaluate the defect concentration based on composition, temperature,
and defect energies using the "Dilute Solution Model"
Reference:
    C. Woodward, M. Asta, G. Kresse and J. Hafner.
    "Density of constitutional and thermal point defects in L12 Al3Sc,"
    Physical Review B, 63, 094103, 2001,
"""

__author__ = 'Bharat Medasani, Enze Chen'
__version__ = "0.3"
__maintainer__ = "Enze Chen"
__email__ = "chenze@berkeley.edu"
__status__ = "Beta"
__date__ = "2020/06/25"

import sys
import copy
import numpy as np
from six.moves import zip
from monty.fractions import gcd

try:
    import sympy
    from sympy import Symbol, Integer, Float, Matrix, exp, Eq
except:
    raise ImportError('Sympy module cannot be found.')

# physical constants
k_B = 8.6173324e-5  # eV/K

# Check the inputs
def check_input(def_list):
    """Check that all defect structures in list are not None.

    Args:
        def_list (list): List of defect structures

    Returns:
        True if all defect structures are present.
    """
    for defect in def_list:
        if not defect:
            return False
    return True

def dilute_solution_model(structure, e0, vac_defs, antisite_defs, T, trial_chem_pot = None, generate = 'plot'):
    """Compute the defect densities using the dilute solution model.

    Args:
        structure: pymatgen.core.structure.Structure object representing the
            primitive or unitcell of the crystal.
        e0 (float): The total energy of the undefected system.
            This is E0 from a VASP calculation.
        vac_defs (list): Vacancy defect parameters in the dictionary format.
            The keys of the dict associated with each vacancy defect are
            1) site_index, 2) site_specie, 3) site_multiplicity, and
            4) energy. 1-3 can be obtained from the
            pymatgen.analysis.defects.point_defects.Vacancy class.
            Site index is expected to start with 1 (Fortran index).
        antisite_defs (list): Antisite defect parameters in the dictionary
            format. The keys of the dict associated with each antisite defect
            are 1) site_index, 2) site_specie, 3) site_multiplicity,
            4) substitution_specie, and 5) energy. 1-3 can be obtained
            from the pymatgen.analysis.defects.point_defects.Vacancy class.
        T (float): Temperature in Kelvin
        trial_chem_pot (dict): Trial chemical potentials to speedup
            the plot generation. Format is {el1:mu1,...}. Optional.
        generate (string): Options are 'plot' or 'energy'
            Chemical potentials are also returned with the 'energy' option.
            If the 'energy' option is not chosen, a plot is generated.

    Returns:
        If generate='plot', the plot data is generated and returned in
        HighCharts format.
        If generate='energy', defect formation enthalpies and chemical
        potentials are returned.
    """

    if not check_input(vac_defs):
        raise ValueError('Vacancy energy is not defined')
    if not check_input(antisite_defs):
        raise ValueError('Antisite energy is not defined')

    formation_energies = {}
    formation_energies['vacancies'] = copy.deepcopy(vac_defs)
    formation_energies['antisites'] = copy.deepcopy(antisite_defs)
    for vac in formation_energies['vacancies']:
        del vac['energy']
    for asite in formation_energies['antisites']:
        del asite['energy']

    # Setup the system
    site_species = [vac_def['site_specie'] for vac_def in vac_defs]
    multiplicity = [vac_def['site_multiplicity'] for vac_def in vac_defs]
    m = len(set(site_species))  # distinct species
    n = len(vac_defs)           # inequivalent sites
    # print(f'Site species: {site_species}')
    # print(f'Multiplicity: {multiplicity}')
    # print(f'Total number of distinct species: {m}')
    # print(f'Total number of inequivalent sites: {n}')

    # Reduce the system and associated parameters such that only distinctive
    # atoms are retained
    comm_div = gcd(*tuple(multiplicity))
    multiplicity = [val / comm_div for val in multiplicity]
    e0 = e0 / comm_div
    T = Float(T)
    # print(f'Energy: {e0}')

    c0 = np.diag(np.ones(n))
    mu = [Symbol(f'mu{i}') for i in range(m)]
    # print(f'Mu list: {mu}')

    # Generate maps for hashing
    # Generate specie->mu map and use it for site->mu map
    specie_order = []       # Contains hash for site->mu map  e.g. [Al, Al, V]
    site_specie_set = set()     # e.g. {V, Al}
    for i in range(n):
        site_specie  = site_species[i]
        if site_specie not in site_specie_set:
            site_specie_set.add(site_specie)
            specie_order.append(site_specie)
    site_mu_map = []            # e.g. [mu0, mu0, mu1] where mu0->Al, and mu1->V
    for i in range(n):
        site_specie  = site_species[i]
        j = specie_order.index(site_specie)
        site_mu_map.append(j)
    specie_site_index_map = []  # e.g. [(0, 2), (2, 3)] for Al and V
    for i in range(m):
        low_ind = site_species.index(specie_order[i])
        if i < m-1:
            high_ind = site_species.index(specie_order[i+1])
        else:
            high_ind = n
        specie_site_index_map.append((low_ind, high_ind))
    # print(f'Specie order: {specie_order}')
    # print(f'Site specie set: {site_specie_set}')
    # print(f'Site mu map: {site_mu_map}')
    # print(f'Specie site index map: {specie_site_index_map}')

    """
    dC: delta concentration matrix:
    dC[i,j,k]: Concentration change of atom i, due to presence of atom
               j on lattice site k.
    Special case is [i,i,i] which is considered as vacancy.
    Few cases: (1) dC[i,i,i] = -1 due to being vacancy special case
               (2) dC[k,k,i] = +1 due to increment in k at i lattice if i
                                  lattice type is of different element
               (3) dC[i,k,i] = -1 due to decrement of ith type atom due to
                                  presence of kth type atom on ith sublattice
                                  and kth type atom specie is different from
                                  ith sublattice atom specie
               (4) dC[i,k,k] =  0 due to no effect on ith type atom
               (5) dC[i,j,k] =  0 if i != j != k
    """
    dC = np.zeros((n, n, n), dtype=np.int)
    for i in range(n):
        for j in range(n):
            for k in range(n):
                # case (2)
                if i == j and site_species[j] != site_species[k]:
                    dC[i, j, k] = 1
                # case (1) and (3)
                if i == k:
                    dC[i, j, k] = -1
                # case (4)
                if i != j and site_species[j] == site_species[k]:
                    dC[i, j, k] = 0
    # print(f'Delta concentration matrix:\n{dC}')

    # dE matrix: Flip energies (or raw defect energies)
    els = site_species.copy()
    dE = [[0 for _ in range(n)] for _ in range(n)]
    for j in range(n):
        for i in range(n):
            if i == j:
                dE[i][j] = vac_defs[i]['energy']
            else:
                sub_specie = vac_defs[i]['site_specie']
                site_specie = vac_defs[j]['site_specie']
                if site_specie == sub_specie:
                    dE[i][j] = 0
                else:
                    for as_def in antisite_defs:
                        if int(as_def['site_index']) == j+1 and \
                           sub_specie == as_def['substitution_specie']:
                            dE[i][j] = as_def['energy']
                            break
    dE = np.array(dE)
    # print(f'Delta energies matrix:\n{dE}')

    # Initialization for concentrations
    # c(i, p) == presence of ith type atom on pth type site
    c = sympy.zeros(n, n)
    for i in range(n):
        for p in range(n):
            c[i, p] = Integer(c0[i, p])
            site_flip_contribs = []
            for epi in range(n):
                sum_mu = sum([mu[site_mu_map[j]] * Integer(dC[j, epi, p]) \
                              for j in range(n)])
                flip = Integer(dC[i, epi, p]) * \
                       exp(-(dE[epi, p] - sum_mu) / (k_B * T))
                if flip not in site_flip_contribs:
                    site_flip_contribs.append(flip)
                    c[i, p] += flip
    total_c = []
    for ind in specie_site_index_map:
        val = 0
        for i in range(*ind):
            val += sum([c[i, j] * multiplicity[j] for j in range(n)])
        total_c.append(val)
    c_ratio = [total_c[-1] / total_c[i] for i in range(m)]
    # print(f'Concentration matrix:\n{c}')
    # print(f'c_ratio:\n{c_ratio}')

    # Expression for Omega, the Grand Potential
    omega1 = e0 - sum([mu[site_mu_map[i]] * c0[i, i] * multiplicity[i] \
                       for i in range(n)])
    omega2 = 0
    used_dEs = []
    for p_r in range(n):
        for epi in range(n):
            sum_mu = sum([mu[site_mu_map[j]] * \
                          Float(dC[j, epi, p_r]) for j in range(n)])
            if p_r != epi and site_mu_map[p_r] == site_mu_map[epi]:
                continue
            if dE[epi, p_r] not in used_dEs:
                omega2 += k_B * T * multiplicity[p_r] * \
                          exp(-(dE[epi, p_r] - sum_mu) / (k_B * T))
                used_dEs.append(dE[epi, p_r])
    omega = omega1 - omega2
    # print(f'Omega: {omega}')

    # Compute composition range
    li = specie_site_index_map[0][0]
    hi = specie_site_index_map[0][1]
    comp1_min = sum(multiplicity[li:hi])/sum(multiplicity) * 100 - 1
    comp1_max = sum(multiplicity[li:hi])/sum(multiplicity) * 100 + 1
    delta = float(comp1_max - comp1_min) / 120.0    # dc = 1/60
    yvals = []
    for comp1 in np.arange(comp1_min, comp1_max+delta, delta):
        comp2 = 100 - comp1
        y = comp2 / comp1
        yvals.append(y)
    # print(f'Composition [min, max]: [{comp1_min}, {comp1_max}]')

    def reduce_mu():
        omega = [e0 - sum([mu[site_mu_map[i]] * sum(c0[i, :]) \
                           for i in range(n)])]
        x = sympy.solve(omega)
        return x

    def compute_mus_by_search():
        # Compute trial mu
        mu_red = reduce_mu()
        specie_concen = [sum(multiplicity[ind[0]:ind[1]]) \
                         for ind in specie_site_index_map]
        y_vect = [specie_concen[-1] / specie_concen[i] for i in range(m)]
        vector_func = [y_vect[i] - c_ratio[i] for i in range(m-1)]
        vector_func.append(omega)
        min_diff = 1e10
        mu_vals = None
        c_val = None
        m1_min = -20.0
        if e0 > 0:
            m1_max = 10            # Search space needs to be modified
        else:
            m1_max = 0
        for m1 in np.arange(m1_min, m1_max, 0.01):
            m0 = mu_red[mu[0]].subs(mu[-1], m1)

            try:
                x = sympy.nsolve(vector_func, mu, [m0, m1])
            except:
                continue

            c_val = c.subs(dict(zip(mu,x)))
            specie_concen = []
            for ind in specie_site_index_map:
                specie_concen.append(sum([sum(c_val[i, :]) \
                                          for i in range(*ind)]))
            y_comp = [specie_concen[-1] / specie_concen[i] for i in range(m)]
            diff = np.sqrt(sum([pow(abs(y_comp[i] - y_vect[i]), 2) \
                                for i in range(m)]))
            if diff < min_diff:
                min_diff = diff
                mu_vals = x

        if mu_vals:
            mu_vals = [float(mu_val) for mu_val in mu_vals]
        else:
            raise ValueError()
        return mu_vals

    def compute_def_formation_energies():
        i = 0
        for vac_def in vac_defs:
            site_specie = vac_def['site_specie']
            ind = specie_order.index(site_specie)
            uncor_energy = vac_def['energy']
            formation_energy = uncor_energy + mu_vals[ind]
            formation_energies['vacancies'][i]['formation_energy'] = formation_energy
            specie_ind = site_mu_map[i]
            indices = specie_site_index_map[specie_ind]
            specie_ind_del = indices[1] - indices[0]
            cur_ind = i - indices[0] + 1
            if not specie_ind_del-1:
                label = '$V_{' + site_specie + '}$'
            else:
                label = '$V_{' + site_specie + '_' + str(cur_ind) + '}$'
            formation_energies['vacancies'][i]['label'] = label
            i += 1
        i = 0
        for as_def in antisite_defs:
            site_specie = as_def['site_specie']
            sub_specie = as_def['substitution_specie']
            ind1 = specie_order.index(site_specie)
            ind2 = specie_order.index(sub_specie)
            uncor_energy = as_def['energy']
            formation_energy = uncor_energy + mu_vals[ind1] - mu_vals[ind2]
            formation_energies['antisites'][i]['formation_energy'] = formation_energy
            specie_ind = site_mu_map[i]
            indices = specie_site_index_map[specie_ind]
            specie_ind_del = indices[1] - indices[0]
            cur_ind = i - indices[0] + 1
            if not specie_ind_del-1:
                label = '$' + sub_specie + '_{' + site_specie + '}$'
            else:
                label = '$' + sub_specie + '_{' + site_specie + '_' + str(cur_ind) + '}$'
            formation_energies['antisites'][i]['label'] = label
            i += 1
        return formation_energies

    # If generate option is energy compute effective formation energies
    # at ideal stoichiometry and return the formation energies and chem pot.
    if generate == 'energy':
        print('Using energy generate method.')
        if not trial_chem_pot:
            mu_vals = compute_mus_by_search()
        else:
            try:
                mu_vals = [trial_chem_pot[element] for element in specie_order]
            except:
                mu_vals = compute_mus()

        formation_energies = compute_def_formation_energies()
        mu_dict = dict(zip(specie_order, mu_vals))
        return formation_energies, mu_dict

    if not trial_chem_pot:
        print('No trial chemical potential is given.')
        # Try computing mus by assuming one of the defects is dominant at 0.01
        # concen.  First vacancy is tried and then antisite

        # Generate trial mus assuming vacancy as dominant defect
        # for specie-0 at lower yval
        li0 = specie_site_index_map[0][0]
        hi0 = specie_site_index_map[0][1]
        li1 = specie_site_index_map[1][0]
        hi1 = specie_site_index_map[1][1]
        spec_mult = [sum(multiplicity[li0:hi0]), sum(multiplicity[li1:hi1])]
        ln_def_conc = 4.60517       # -ln(0.01)
        for i in range(li0, hi0):
            vac_flip_en =  vac_defs[i]['energy']
            mu_vals = [ln_def_conc * k_B * T - vac_flip_en]
            mu_vals.append((e0 - spec_mult[0] * mu_vals[0]) / spec_mult[1])
            comp_ratio = yvals[0]

            # Test if the trial mus are good
            vector_func = [comp_ratio - c_ratio[0]]
            vector_func.append(omega)
            try:
                mu_vals = sympy.nsolve(vector_func, mu, mu_vals)
                if mu_vals:
                    mu_vals = [float(mu_val) for mu_val in mu_vals]
                break
            except:     # Go for antisite as dominant defect
                mu_gs = [Symbol(f'mu_gs{j}') for j in range(m)]
                eqs = [mu_gs[0] - mu_gs[1] - (ln_def_conc * k_B * T - \
                       antisite_defs[i]['energy'])]
                eqs.append(spec_mult[0] * mu_gs[0] + spec_mult[1] * mu_gs[1] - e0)
                x = sympy.solve(eqs, mu_gs)
                mu_vals = [x[key] for key in sorted(x.keys(), key=lambda inp: inp.name)]

                try:
                    mu_vals = sympy.nsolve(vector_func, mu, mu_vals)
                    if mu_vals:
                        mu_vals = [float(mu_val) for mu_val in mu_vals]
                    break
                except:     # Go to the default option (search the space)
                    pass
        else:
            mu_vals = compute_mus_by_search()
    else:
        try:
            mu_vals = [trial_chem_pot[element] for element in specie_order]
        except:
            mu_vals = compute_mus_by_search()
    print(f'Trial mu_vals: {mu_vals}')

    # COMPUTE MU's FOR ALL COMPOSITION RATIOS in the range
    # +/- 1% from the stoichiometry. MAIN SOLVER!!
    result = {}
    failed_y, failed_i = [], []
    for i, y in enumerate(yvals):
        vector_func = [y - c_ratio[0]]
        vector_func.append(omega)
        try:
            x = sympy.nsolve(vector_func, mu, mu_vals)
            if x:
                mu_vals = [float(mu_val) for mu_val in x]
        except:
            failed_y.append(y)
            failed_i.append(i)
            continue
        result[y] = mu_vals
        x = None
    print(f'Failed {len(failed_i)} times.')

    def get_next_mu_val(i):
        if i >= len(yvals):
            return None

        y =  yvals[i+1]
        x = result.get(y, None)
        if x:
            mu_vals = [float(mu_val) for mu_val in x]
            return mu_vals
        else:
            return get_next_mu_val(i+1)

    def get_prev_mu_val(i):
        if i <= 0:
            return None

        y =  yvals[i-1]
        x = result.get(y, None)
        if x:
            mu_vals = [float(mu_val) for mu_val in x]
            return mu_vals
        else:
            return get_next_mu_val(i-1)

    # Try to get better trial mus for failed cases
    for j in range(len(failed_y)):
        i = failed_i[j]

        prev_mu_val = get_prev_mu_val(i)
        if not prev_mu_val:
            continue
        next_mu_val = get_next_mu_val(i)
        if not next_mu_val:
            continue

        y = failed_y[j]
        vector_func = [y - c_ratio[0]]
        vector_func.append(omega)
        trial_mu = list(map(lambda x: float(sum(x)) / len(x), \
                zip(prev_mu_val, next_mu_val)))
        try:
            x = sympy.nsolve(vector_func, mu, trial_mu)
            if x:
                mu_vals = [float(mu_val) for mu_val in x]
        except:
            continue
        result[y] = mu_vals
        x = None

    if len(result.keys()) < len(yvals)/2:
        raise ValueError('Not sufficient data.')

    res = []
    new_mu_dict = {}
    # COMPUTE THE CONCENTRATION for all the compositions
    for key in sorted(result.keys()):
        mu_val = result[key]
        total_c_val = [total_c[i].subs(dict(zip(mu, mu_val))) \
                       for i in range(len(total_c))]
        c_val = c.subs(dict(zip(mu, mu_val)))
        res1 = [float(total_c_val[0] / sum(total_c_val))]
        # Concentration of first element/over total concentration
        new_mu_dict[res1[0]] = mu_val
        # sum_c0 = sum([c0[i, i] for i in range(n)])
        for i in range(n):
            for j in range(n):
                if i == j:              # Vacancy
                    vac_conc = float(exp(-(mu_val[site_mu_map[i]] + dE[i, i])/(k_B * T)))
                    res1.append(vac_conc)
                    if vac_conc > 1.0:
                        print('Warning! Vacancy concentration is > 1.')
                else:                   # Antisite
                    anti_conc = float(c_val[i, j] / c0[j, j])
                    res1.append(anti_conc)
                    if anti_conc > 1.0:
                        print('Warning! Antisite concentration is > 1.')
        res.append(res1)

    res = np.array(res)
    dtype = [(str('x'), np.float64)] + [(f'y{i}{j}', np.float64) \
                                        for i in range(n) for j in range(n)]
    res1 = np.sort(res.view(dtype), order=[str('x')], axis=0)

    conc_data = {}
    # Because all the plots have identical x-points, we store them in a single array
    conc_data['x'] = [dat[0][0] for dat in res1]         # x-axis data
    # Element whose composition is varied. For x-label
    conc_data['x_label'] = els[0] + " mole fraction"
    conc_data['y_label'] = "Point defect concentration"
    conc = [[[] for _ in range(n)] for _ in range(n)]
    for i in range(n):
        for j in range(n):
            # n x n array where each element is a list of concentrations
            conc[i][j] = [dat[0][i * n + j + 1] for dat in res1]

    # Get the vacancies concentration for each site
    y_data = []
    for i in range(n):
        data = conc[i][i]
        site_specie = els[i]
        specie_ind = site_mu_map[i]
        indices = specie_site_index_map[specie_ind]
        specie_ind_del = indices[1] - indices[0]
        cur_ind = i - indices[0] + 1
        vac_string = "$Vac_{"
        if not specie_ind_del-1:
            label = f'{vac_string}{site_specie}}}$'
        else:
            label = f'{vac_string}{site_specie}_{cur_ind}}}$'
        y_data.append({'data':data, 'name':label})

    # Get the antisites concentration for each site
    for i in range(n):
        site_specie = els[i]
        specie_ind = site_mu_map[i]
        indices = specie_site_index_map[specie_ind]
        specie_ind_del = indices[1] - indices[0]
        cur_ind = i - indices[0] + 1
        for j in range(m):
            sub_specie = specie_order[j]
            if sub_specie == site_specie:
                continue
            if not specie_ind_del-1:
                label = f'${sub_specie}_{{{site_specie}}}$'
            else:
                label = f'${sub_specie}_{{{site_specie}_{cur_ind}}}$'
            inds = specie_site_index_map[j]
            # Sum concentrations of multi-site species with same composition
            data = np.sum([conc[ind][i] for ind in range(*inds)], axis=0)
            data = data.tolist()
            y_data.append({'data':data, 'name':label})

    conc_data['y'] = y_data

    # Compute the vacancy formation energies
    def compute_vac_formation_energies(mu_vals):
        en = []
        for vac_def in vac_defs:
            site_specie = vac_def['site_specie']
            ind = specie_order.index(site_specie)
            uncor_energy = vac_def['energy']
            formation_energy = uncor_energy + mu_vals[ind]
            en.append(float(formation_energy))
        return en

    en_res = []
    for key in sorted(new_mu_dict.keys()):
        mu_val = new_mu_dict[key]
        en_res.append(compute_vac_formation_energies(mu_val))

    en_data = {'x_label':els[0] + ' mole fraction'}
    en_data['x'] = [dat[0][0] for dat in res1]         # x-axis data

    # Get vacancy formation energy for each site
    y_data = []
    for i, vac_def in enumerate(vac_defs):
        data = [data[i] for data in en_res]
        site_specie = vac_def['site_specie']
        specie_ind = site_mu_map[i]
        indices = specie_site_index_map[specie_ind]
        specie_ind_del = indices[1] - indices[0]
        cur_ind = i - indices[0] + 1
        vac_string = "$Vac_{"
        if not specie_ind_del-1:
            label = vac_string + site_specie + '}$'
        else:
            label = vac_string + site_specie + '_' + str(cur_ind) + '}$'
        y_data.append({'data':data, 'name':label})

    # Compute the antisite formation energies
    def compute_as_formation_energies(mu_vals):
        en = []
        for as_def in antisite_defs:
            site_specie = as_def['site_specie']
            sub_specie = as_def['substitution_specie']
            ind1 = specie_order.index(site_specie)
            ind2 = specie_order.index(sub_specie)
            uncor_energy = as_def['energy']
            formation_energy = uncor_energy + mu_vals[ind1] - mu_vals[ind2]
            en.append(formation_energy)
        return en

    en_res = []
    for key in sorted(new_mu_dict.keys()):
        mu_val = new_mu_dict[key]
        en_res.append(compute_as_formation_energies(mu_val))

    for i, as_def in enumerate(antisite_defs):
        data = [data[i] for data in en_res]
        site_specie = as_def['site_specie']
        sub_specie = as_def['substitution_specie']
        specie_ind = site_mu_map[i]
        indices = specie_site_index_map[specie_ind]
        specie_ind_del = indices[1] - indices[0]
        cur_ind = i - indices[0] + 1
        if not specie_ind_del-1:
            label = '$' + sub_specie + '_{' + site_specie + '}$'
        else:
            label = '$' + sub_specie + '_{' + site_specie + '_' + \
                    str(cur_ind) + '}$'
        y_data.append({'data':data, 'name':label})

    en_data['y'] = y_data

    # Return chemical potential as well
    mu_data = {'x_label':els[0] + ' mole fraction', 'x':[]}
    mu_data['x'] = [dat[0][0] for dat in res1]         # x-axis data

    y_data = []
    for j in range(m):
        specie = specie_order[j]
        mus = [new_mu_dict[key][j] for key in sorted(new_mu_dict.keys())]
        y_data.append({'data':mus, 'name':specie})
    mu_data['y'] = y_data

    return conc_data, en_data, mu_data

def compute_defect_density(structure, e0, vac_defs, antisite_defs, T=800, \
                           trial_chem_pot = None, plot_style = "highcharts"):
    """
    Wrapper for the dilute_solution_model.
    The computed plot data is prepared based on plot_style.

    Args:
        structure: pymatgen.core.structure.Structure object representing the
            primitive or unitcell of the crystal.
        e0: The total energy of the undefected system.
            This is E0 from VASP calculation.
        vac_defs: List of vacancy defect parameters in the dictionary format.
            The keys of the dict associated with each vacancy defect are
            1) site_index, 2) site_specie, 3) site_multiplicity, and
            4) energy. 1-3 can be obtained from
            pymatgen.analysis.defects.point_defects.Vacancy class.
            Site index is expected to start with 1 (fortran index).
        antisite_defs: List of antisite defect parameters in the dictionary
            format. The keys of the dict associated with each antisite defect
            are 1) site_index, 2) site_specie, 3) site_multiplicity,
            4) substitution_specie, and 5) energy. 1-3 can be obtained
            from pymatgen.analysis.defects.point_defects.Vacancy class.
        T: Temperature in Kelvin
        trial_chem_pot (optional): Trial chemical potentials to speedup
            the plot generation. Format is {el1:mu1, ...}
        plot_style (string): Allowed options are
            1) highcharts (default)
            2) gnuplot

    Returns:
        The plot data is generated and returned in asked format.
    """
    conc_data, en_data, mu_data = dilute_solution_model(
        structure, e0, vac_defs, antisite_defs, T, trial_chem_pot=trial_chem_pot)

    if plot_style == 'highcharts':
        "Energy data is ignored in this mode"
        hgh_chrt_data = {}
        hgh_chrt_data['xAxis'] = conc_data['x_label']
        hgh_chrt_data['yAxis'] = conc_data['y_label']

        series = []
        x = conc_data['x']
        for y_data in conc_data['y']:
            y = y_data['data']
            xy = zip(x,y)
            xy = [list(el) for el in xy]
            name = y_data['name'].strip('$')
            flds= name.split('_')
            def_string = flds[0]
            site_string = flds[1].strip('{}')
            name = def_string + "<sub>" + site_string + "</sub>"
            # series.append({'data':xy, 'name':y_data['name']})
            series.append({'data':xy, 'name':name})
        hgh_chrt_data['series'] = series
        return hgh_chrt_data
    elif plot_style == 'gnuplot':
        def data_to_rows(inp_data):
            rows = []
            labels = []
            labels.append(inp_data['x_label'])
            labels += [y['name'] for y in inp_data['y']]
            rows.append('#' + '\t'.join(labels))
            m = len(inp_data['x'])
            for i in range(m):
                data = []
                data.append(inp_data['x'][i])
                data += [y['data'][i] for y in inp_data['y']]
                data = [float(x) for x in data]
                rows.append('\t'.join(list(map(str, data))))
            return rows
        conc_rows = data_to_rows(conc_data)
        en_rows = data_to_rows(en_data)
        mu_rows = data_to_rows(mu_data)

        return conc_rows, en_rows, mu_rows
    else:
        raise ValueError(f'Plot style {plot_style} is not supported.')

# solute_site_preference_finder is based on dilute_solution_model and so most
# of the code is same. However, differences exist in setup and processing,
# hence the new function
def solute_site_preference_finder(structure, e0, vac_defs, antisite_defs, T, \
    solute_defs, solute_concen=0.01, trial_chem_pot = None):
    """
    Compute the solute defect densities using dilute solution model.
    Args:
        structure: pymatgen.core.structure.Structure object representing the
            primitive or unitcell of the crystal.
        e0: The total energy of the undefected system.
            This is E0 from VASP calculation.
        T: Temperature in Kelvin
        vac_defs: List of vacancy defect parameters in the dictionary format.
            The keys of the dict associated with each vacancy defect are
            1) site_index, 2) site_specie, 3) site_multiplicity, and
            4) energy. 1-3 can be obtained from
            pymatgen.analysis.defects.point_defects.Vacancy class.
            Site index is expected to start with 1 (fortran index).
        antisite_defs: List of antisite defect parameters in the dictionary
            format. The keys of the dict associated with each antisite
            defect are 1) site_index, 2) site_specie, 3) site_multiplicity,
            4) substitution_specie, and 5) energy. 1-3 can be obtained
            from pymatgen.analysis.defects.point_defects.Vacancy class.
        solute_defs: List of solute defect parameters in the dictionary
            format. Similar to that of antisite defs, with solute specie
            specified in substitution_specie
        solute_concen: Solute concentration (in fractional value)
        trial_chem_pot: Trial chemical potentials to speed up the plot
            generation. Format is {el1:mu1,...}

    Returns:
        plot_data: The data for plotting the solute defect concentration.
    """

    if not check_input(vac_defs):
        raise ValueError('Vacancy energy is not defined')
    if not check_input(antisite_defs):
        raise ValueError('Antisite energy is not defined')

    # Setup the system
    site_species = [vac_def['site_specie'] for vac_def in vac_defs]
    solute_specie = solute_defs[0]['substitution_specie']
    site_species.append(solute_specie)
    multiplicity = [vac_def['site_multiplicity'] for vac_def in vac_defs]
    m = len(set(site_species))  # distinct species
    n = len(vac_defs)           # inequivalent sites
    # print(f'Site species: {site_species}')
    # print(f'Multiplicity: {multiplicity}')
    # print(f'Total number of distinct species: {m}')
    # print(f'Total number of inequivalent sites: {n}')

    # Reduce the system and associated parameters such that only distinctive
    # atoms are retained
    comm_div = gcd(*tuple(multiplicity))
    multiplicity = [val / comm_div for val in multiplicity]
    multiplicity.append(0)
    e0 = e0 / comm_div
    T = Float(T)
    # print(f'Energy: {e0}')

    c0 = np.diag(np.ones(n+1))
    c0[n, n] = 0
    mu = [Symbol(f'mu{i}') for i in range(m)]
    # print(f'Mu list: {mu}')

    # Generate maps for hashing
    # Generate specie->mu map and use it for site->mu map
    specie_order = []       # Contains hash for site->mu map    Eg: [Al, Ni, Fe]
    site_specie_set = set()             # e.g. {Ni, Al, Fe}
    for i in range(len(site_species)):
        site_specie = site_species[i]
        if site_specie not in site_specie_set:
            site_specie_set.add(site_specie)
            specie_order.append(site_specie)
    site_mu_map = []     # Eg: [mu0, mu1, mu2] where mu0->Al, mu1->Ni, mu2->Fe
    for i in range(len(site_species)):
        site_specie = site_species[i]
        j = specie_order.index(site_specie)
        site_mu_map.append(j)
    specie_site_index_map = []      # Eg: [(0,1), (1,2), (2,3)] for [Al, Ni ,Fe]
    for i in range(m):
        low_ind = site_species.index(specie_order[i])
        if i < m-1:
            high_ind = site_species.index(specie_order[i+1])
        else:
            high_ind = len(site_species)
        specie_site_index_map.append((low_ind, high_ind))
    # print(f'Specie order: {specie_order}')
    # print(f'Site specie set: {site_specie_set}')
    # print(f'Site mu map: {site_mu_map}')
    # print(f'Specie site index map: {specie_site_index_map}')

    """
    dC: delta concentration matrix:
    dC[i,j,k]: Concentration change of atom i, due to presence of atom
               j on lattice site k.
    Special case is [i,i,i] which is considered as vacancy.
    Few cases: (1) dC[i,i,i] = -1 due to being vacancy special case
               (2) dC[k,k,i] = +1 due to increment in k at i lattice if i
                                  lattice type is of different element
               (3) dC[i,k,i] = -1 due to decrement of ith type atom due to
                                  presence of kth type atom on ith sublattice
                                  and kth type atom specie is different from
                                  ith sublattice atom specie
               (4) dC[i,k,k] =  0 due to no effect on ith type atom
               (5) dC[i,j,k] =  0 if i != j != k
    """
    dC = np.zeros((n+1, n+1, n), dtype=np.int)
    for i in range(n):
        for k in range(n):
            for j in range(n+1):
                # case (2)
                if i == j and site_species[j] != site_species[k]:
                    dC[i, j, k] = 1
                # case (1) & (3)
                if i == k:
                    dC[i, j, k] = -1
                # case (4)
                if i != j and site_species[j] == site_species[k]:
                    dC[i, j, k] = 0
    # solute case
    dC[n, n, :] = 1
    # print(f'Delta concentration matrix:\n{dC}')

    # dE matrix: Flip energies (or raw defect energies)
    els = site_species.copy()
    dE = [[0 for _ in range(n)] for _ in range(n+1)]
    for j in range(n):
        site_specie = vac_defs[j]['site_specie']
        # Vacancy and antisite energies
        for i in range(n):
            if i == j:
                dE[i][j] = vac_defs[i]['energy']
            else:
                sub_specie = vac_defs[i]['site_specie']
                if site_specie == sub_specie:
                    dE[i][j] = 0
                else:
                    for as_def in antisite_defs:
                        if int(as_def['site_index']) == j+1 and \
                           sub_specie == as_def['substitution_specie']:
                            dE[i][j] = as_def['energy']
                            break
        # Solute energies
        for solute_def in solute_defs:
            def_site_ind = int(solute_def['site_index'])
            def_site_specie = solute_def['site_specie']
            if def_site_specie == site_specie and def_site_ind == j+1:
                dE[n][j] = solute_def['energy']
                break
    dE = np.array(dE)
    # print(f'Delta energies matrix:\n{dE}')

    # Initialization for concentrations
    # c(i, p) == presence of ith type atom on pth type site
    c = sympy.zeros(n+1, n)
    for i in range(n+1):
        for p in range(n):
            c[i, p] = Integer(c0[i, p])
            site_flip_contribs = []
            for epi in range(n+1):
                sum_mu = sum([mu[site_mu_map[j]] * Integer(dC[j, epi, p]) \
                              for j in range(n+1)])
                flip = Integer(dC[i, epi, p]) * \
                       exp(-(dE[epi, p] - sum_mu) / (k_B * T))
                if flip not in site_flip_contribs:
                    site_flip_contribs.append(flip)
                    c[i, p] += flip
    total_c = []
    for ind in specie_site_index_map:
        val = 0
        for i in range(*ind):
            val += sum([c[i, j] * multiplicity[j] for j in range(n)])
        total_c.append(val)
    c_ratio = [total_c[i] / sum(total_c) for i in range(m)]  # different ratio from DSM!
    # print(f'Concentration matrix:\n{c}')
    # print(f'c_ratio:\n{c_ratio}')

    # Similar, just without the solute specie
    host_c = sympy.zeros(n, n)
    for i in range(n):
        for p in range(n):
            host_c[i, p] = Integer(c0[i, p])
            site_flip_contribs = []
            for epi in range(n):
                sum_mu = sum([mu[site_mu_map[j]] * Integer(dC[j, epi, p]) \
                              for j in range(n)])
                flip = Integer(dC[i, epi, p]) * \
                       exp(-(dE[epi, p] - sum_mu) / (k_B * T))
                if flip not in site_flip_contribs:
                    site_flip_contribs.append(flip)
                    host_c[i, p] += flip
    host_total_c = []
    for ind in specie_site_index_map[:-1]:
        val = 0
        for i in range(*ind):
            val += sum([host_c[i, j] * multiplicity[j] for j in range(n)])
        host_total_c.append(val)
    host_c_ratio = [host_total_c[i] / sum(host_total_c) for i in range(m-1)]

    # Expression for Omega, the Grand Potential
    omega1 = e0 - sum([mu[site_mu_map[i]] * c0[i, i] * multiplicity[i] \
                       for i in range(n)])
    omega = copy.deepcopy(omega1)
    used_dEs = []
    for p_r in range(n):
        for epi in range(n):
            sum_mu1 = sum([mu[site_mu_map[j]] * \
                          Float(dC[j, epi, p_r]) for j in range(n)])
            sum_mu = sum_mu1 - mu[site_mu_map[n]] * dC[n, epi, p_r]
            if p_r != epi and site_mu_map[p_r] == site_mu_map[epi]:
                continue
            if dE[epi, p_r] not in used_dEs:
                omega1 -= k_B * T * multiplicity[p_r] * \
                          exp(-(dE[epi, p_r] - sum_mu1) / (k_B * T))
                omega -=  k_B * T * multiplicity[p_r] * \
                          exp(-(dE[epi, p_r] - sum_mu) / (k_B * T))
                used_dEs.append(dE[epi, p_r])
    # print(f'Omega: {omega}')

    # Compute composition ranges
    max_host_specie_concen = 1 - solute_concen
    specie_concen = [sum(multiplicity[ind[0]:ind[1]]) \
                     for ind in specie_site_index_map]
    host_specie_concen_ratio = [specie_concen[i] / sum(specie_concen) * \
                                max_host_specie_concen for i in range(m)]
    host_specie_concen_ratio[-1] = solute_concen
    li = specie_site_index_map[0][0]
    hi = specie_site_index_map[0][1]
    comp1_min = sum(multiplicity[li:hi]) / sum(multiplicity) * \
                max_host_specie_concen - 0.01
    comp1_max = sum(multiplicity[li:hi]) / sum(multiplicity) * \
                max_host_specie_concen + 0.01
    delta = (comp1_max - comp1_min) / 50.0  # 0.04%
    # print(f'Composition range: [{comp1_min}, {comp1_max}]')
    # print(f'delta: {delta}')
    # print(f'max_host_specie_concen: {max_host_specie_concen}')
    # print(f'specie_concen: {specie_concen}')
    # print(f'host_specie_concen_ratio: {host_specie_concen_ratio}')

    def reduce_mu():
        host_concen = 1 - solute_concen
        new_c0 = c0.astype(float)
        for i in range(n):
            new_c0[i, i] = host_concen * c0[i, i]
        new_c0[n, n] = 2 * solute_concen  # double because of binary host
        omega = [e0 - sum([mu[site_mu_map[i]] * new_c0[i, i] for i in range(n+1)])]
        x = sympy.solve(omega)
        return x

    def compute_solute_mu_by_lin_search(host_mu_vals):
        mu_red = reduce_mu()
        # print(f'Reduced mu solution: {mu_red}')

        y_vect = host_specie_concen_ratio
        vector_func = [y_vect[i] - c_ratio[i] for i in range(m-1)]
        vector_func.append(omega)
        mu_vals = None
        dm = 0.5
        m1_min = -15.0
        if e0 > 0:
            m1_max = 10            # Search space needs to be modified
        else:
            m1_max = 0
        for m1 in np.arange(m1_min, m1_max, dm):
            trial_mus = host_mu_vals + [m1]
            try:
                x = sympy.nsolve(vector_func, mu, trial_mus)
                if x:
                    mu_vals = [float(mu_val) for mu_val in x]
                break
            except:
                continue
        else:
            raise ValueError()
        return mu_vals

    def compute_mus():
        # Compute trial mu
        mu_red = reduce_mu()
        # print(f'Reduced mu solution: {mu_red}')

        y_vect = host_specie_concen_ratio
        vector_func = [y_vect[i] - c_ratio[i] for i in range(m)]
        vector_func.append(omega)
        mu_vals = None
        dm = 0.5
        m_min = -15.0
        if e0 > 0:
            m_max = 10            # Search space needs to be modified
        else:
            m_max = 0
        for m1 in np.arange(m_min, m_max, dm):
            for m2 in np.arange(m_min, m_max, dm):
                m0 = mu_red[mu[0]].subs([(mu[1], m1), (mu[2], m2)])
                try:
                    mu_vals = sympy.nsolve(vector_func, mu, [m0, m1, m2])
                    # Line needs to be modified to include all mus when n > 2
                except:
                    continue
                break
            if mu_vals:
                mu_vals = [float(mu_val) for mu_val in mu_vals]
                break
        else:
            raise ValueError("Couldn't find mus!")
        return mu_vals

    if not trial_chem_pot:
        print('No trial chemical potential is given.')
        # Try computing mus by assuming one of the defects is dominant at 0.01
        # concentration. First vacancy is tried and then antisite.

        # Generate trial mus assuming vacancy as dominant defect
        # for specie-0 at lower yval.
        li0 = specie_site_index_map[0][0]
        hi0 = specie_site_index_map[0][1]
        li1 = specie_site_index_map[1][0]
        hi1 = specie_site_index_map[1][1]
        spec_mult = [sum(multiplicity[li0:hi0]), sum(multiplicity[li1:hi1])]
        ln_def_conc = 4.60517
        # Try to initialize with host mus
        for i in range(li0, hi0):
            vac_flip_en =  vac_defs[i]['energy']
            mu_vals = [ln_def_conc * k_B * T - vac_flip_en]
            mu_vals.append((e0 - spec_mult[0] * mu_vals[0]) / spec_mult[1])
            comp_ratio = comp1_min

            # Test if the trial mus are good
            vector_func = [comp_ratio - host_c_ratio[0]]
            vector_func.append(omega1)
            try:
                # Get host mu values first, then solutes
                host_mu_vals = sympy.nsolve(vector_func, mu[:-1], mu_vals)
                if host_mu_vals:
                    host_mu_vals = [float(mu_val) for mu_val in host_mu_vals]
                compute_solute_mu_by_lin_search(host_mu_vals)
                break
            except:     # Go for antisite as dominant defect
                mu_gs = [Symbol(f'mu_gs{j}') for j in range(m-1)]
                eqs = [mu_gs[0] - mu_gs[1] - \
                       (ln_def_conc * k_B * T - antisite_defs[i]['energy'])]
                eqs.append(spec_mult[0] * mu_gs[0] + spec_mult[1] * mu_gs[1] - e0)
                x = sympy.solve(eqs, mu_gs)
                host_mu_vals = [x[key] for key in sorted(x.keys(), key=lambda inp: inp.name)]

                try:
                    host_mu_vals = sympy.nsolve(vector_func, mu[:-1], host_mu_vals)
                    if host_mu_vals:
                        host_mu_vals = [float(mu_val) for mu_val in host_mu_vals]
                    mu_vals = compute_solute_mu_by_lin_search(host_mu_vals)
                    break
                except:     # Go to the default option (search the space)
                    pass
        else:
            mu_vals = compute_mus()
    else:
        try:
            mu_vals = [trial_chem_pot[element] for element in specie_order]
        except:
            mu_vals = compute_mus()
    print(f'Trial mu_vals: {mu_vals}')

    # COMPUTE MU's FOR ALL COMPOSITION RATIOS in the range
    # +/- 1% from the stoichiometry
    result = {}
    for y in np.arange(comp1_min, comp1_max + delta, delta):
        y_vect = [y, max_host_specie_concen - y, solute_concen]
        vector_func = [y_vect[i] - c_ratio[i] for i in range(1, m)]
        vector_func.append(omega)

        try:
            x = sympy.nsolve(vector_func, mu, mu_vals)
            if x:
                mu_vals = [float(mu_val) for mu_val in x]
        except:
            continue
        result[y] = mu_vals

    res = []
    # COMPUTE THE CONCENTRATION for all the compositions
    for key in sorted(result.keys()):
        mu_val = result[key]
        total_c_val = [total_c[i].subs(dict(zip(mu, mu_val))) \
                       for i in range(len(total_c))]
        c_val = c.subs(dict(zip(mu, mu_val)))
        # Concentration of first element / total concen
        res1 = [float(total_c_val[0] / sum(total_c_val))]
        for i in range(n+1):
            for j in range(n):
                if i == j:              # Vacancy
                    vac_conc = float(exp(-(mu_val[site_mu_map[i]] + dE[i, i])/(k_B * T)))
                    res1.append(vac_conc)
                    if vac_conc > 1.0:
                        print('Warning! Vacancy concentration is > 1.')
                else:                   # Antisite
                    anti_conc = float(c_val[i, j] / c0[j, j])
                    res1.append(anti_conc)
                    if anti_conc > 1.0:
                        print('Warning! Antisite concentration is > 1.')
        res.append(res1)

    res = np.array(res)
    dtype = [(str('x'), np.float64)] + [(f'y{i}{j}', np.float64) \
                                        for i in range(n+1) for j in range(n)]
    res1 = np.sort(res.view(dtype), order=[str('x')], axis=0)

    conc_data = {}
    # Because all the plots have identical x-points, we store them in a single array
    conc_data['x'] = [dat[0][0] for dat in res1]         # x-axis data
    # Element whose composition is varied. For x-label
    conc_data['x_label'] = els[0] + " mole fraction"
    conc_data['y_label'] = "Point defect concentration"
    conc = [[[] for _ in range(n)] for _ in range(n+1)]
    for i in range(n+1): # Append vacancies
        for j in range(n):
            # n+1 x n array where each element is a list of concentrations
            conc[i][j] = [dat[0][i * n + j + 1] for dat in res1]

    y_data = []
    # Get the vacancies concentration for each site
    for i in range(n):
        data = conc[i][i]
        site_specie = els[i]
        specie_ind = site_mu_map[i]
        indices = specie_site_index_map[specie_ind]
        specie_ind_del = indices[1] - indices[0]
        cur_ind = i - indices[0] + 1
        vac_string = "$Vac_{"
        if not specie_ind_del-1:
            label = f'{vac_string}{site_specie}}}$'
        else:
            label = f'{vac_string}{site_specie}_{cur_ind}}}$'
        y_data.append({'data':data, 'name':label})

    # Get the antisites and solute concentration for each site
    for i in range(n):
        site_specie = els[i]
        specie_ind = site_mu_map[i]
        indices = specie_site_index_map[specie_ind]
        specie_ind_del = indices[1] - indices[0]
        cur_ind = i - indices[0] + 1
        for j in range(m):
            sub_specie = specie_order[j]
            if sub_specie == site_specie:
                continue
            if not specie_ind_del-1:
                label = f'${sub_specie}_{{{site_specie}}}$'
            else:
                label = f'${sub_specie}_{{{site_specie}_{cur_ind}}}$'
            inds = specie_site_index_map[j]
            # Sum concentrations of multi-site species with same composition
            data = np.sum([conc[ind][i] for ind in range(*inds)], axis=0)
            data = data.tolist()
            y_data.append({'data':data, 'name':label})

    conc_data['y'] = y_data
    return conc_data

def solute_defect_density(structure, e0, vac_defs, antisite_defs, solute_defs,
    solute_concen=0.01, T=800, trial_chem_pot=None, plot_style="highcharts"):
    """
    Wrapper for the solute_site_preference_finder.
    The computed plot data is prepared based on plot_style.

    Args:
        structure: pymatgen.core.structure.Structure object representing the
            primitive or unit cell of the crystal.
        e0: The total energy of the undefected system.
            This is E0 from the VASP calculation.
        vac_defs: List of vacancy defect parameters in the dictionary format.
            The keys of the dict associated with each vacancy defect are
            1) site_index, 2) site_specie, 3) site_multiplicity, and
            4) energy. 1-3 can be obtained from
            pymatgen.analysis.defects.point_defects.Vacancy class.
            Site index is expected to start with 1 (fortran index).
        antisite_defs: List of antisite defect parameters in the dictionary
            format. The keys of the dict associated with each antisite defect
            are 1) site_index, 2) site_specie, 3) site_multiplicity,
            4) substitution_specie, and 5) energy. 1-3 can be obtained
            from pymatgen.analysis.defects.point_defects.Vacancy class.
        solute_defs: List of solute defect parameters in the dictionary
            format. Similary to that of antisite defs, wtih solute specie
            specified in substitution_specie
        solute_concen: Solute concentration (in fractional value)
        T: Temperature in Kelvin
        trial_chem_pot (optional): Trial chemical potentials to speed up
            the plot generation. Format is {el1:mu1,...}
        plot_style (string): Allowed options are
            1) highcharts (default)
            2) gnuplot

    Returns:
        The plot data is generated and returned in asked format.
    """
    def_conc_data = solute_site_preference_finder(
        structure, e0, vac_defs, antisite_defs, T, solute_defs,
        solute_concen=solute_concen, trial_chem_pot=trial_chem_pot)

    if plot_style == 'highcharts':
        "Energy data is ignored in this mode"
        hgh_chrt_data = {}
        hgh_chrt_data['xAxis'] = def_conc_data['x_label']
        hgh_chrt_data['yAxis'] = def_conc_data['y_label']

        series = []
        x = def_conc_data['x']
        for y_data in def_conc_data['y']:
            y = y_data['data']
            xy = zip(x,y)
            xy = [list(el) for el in xy]
            name = y_data['name'].strip('$')
            flds= name.split('_')
            def_string = flds[0]
            site_string = flds[1].strip('{}')
            name = def_string + "<sub>" + site_string + "</sub>"
            #series.append({'data':xy, 'name':y_data['name']})
            series.append({'data':xy, 'name':name})
        hgh_chrt_data['series'] = series
        return hgh_chrt_data
    elif plot_style == 'gnuplot':
        def data_to_rows(inp_data, y_lbl_flg):
            rows = []
            labels = []
            labels.append(inp_data['x_label'])
            if y_lbl_flg:
                labels.append(inp_data['y_label'])
            else:
                labels += [y['name'] for y in inp_data['y']]
            rows.append('#' + '\t'.join(labels))
            m = len(inp_data['x'])
            for i in range(m):
                data = []
                data.append(inp_data['x'][i])
                data += [y['data'][i] for y in inp_data['y']]
                data = [float(x) for x in data]
                rows.append('\t'.join(list(map(str, data))))
            return rows
        pt_def_conc_rows = data_to_rows(def_conc_data, False)
        return pt_def_conc_rows
    else:
        raise ValueError(f'Plot style {plot_style} is not supported.')

redpajama_set_name: RedPajamaGithub


text:
Lavrov: Russia Not Violating UNSC Resolution by Deploying Jets to Iran
© AP Photo / WarfareWW
https://sputniknews.com/politics/201608171044351514-lavrov-iran-jets/
Russian Foreign Minister Sergei Lavrov said that Moscow is not violating a UN Security Council resolution by deploying jets to Iran to carry out strikes against terrorists in Syria.
"There is no reason to suspect Russia of violating 2231 UNSC resolution," Lavrov said Wednesday.
"According to this resolution, supplies, sale and transfer of certain types on weapons, including combat aircraft, should be agreed with the UNSC. In the case we are discussing, there were no supply, sale or transfer of combat jets to Iran. These jets are are used by the Russian Aerospace Forces to conduct an anti-terrorist operation in the Syrian Arab Republic at the request of the legitimate Syrian leadership."
© Sputnik / Grigory Sysoyev
Russian Su-34 Jets Deployed in Iran Conduct Strikes Against Daesh in Syria's Deir ez-Zor (VIDEO)
The Russian Defense Ministry confirmed on Tuesday that it had deployed Tu-22M3 bombers and Su-34 strike fighters in Iran and these aircraft have already been used to carried out airstrikes against Daesh in Syria.
Following the news, the US State Department said that it is studying whether Moscow violated a UNSC resolution by deploying jets to an Iranian airbase.
"If someone wants to find… [violations] concerning the remaining restrictions on trade and other communication with Iran, we should also study how a huge amount of cash from the US made it into Iran, why bank transfers from the US to Iran in dollars were made that is absolutely prohibited by the US law," Lavrov emphasized.
Lavrov added that parties involved should aim to find a solution to the Syrian crisis. The main task in Syria is to achieve coordination between Russia and the United States, the Russian top diplomat said.
Speaking of his phone conversation with US State Secretary John Kerry on Tuesday, Lavrov confirmed that specific mechanisms to bring to life the agreements reached during Kerry's July 15 visit to Moscow are discussed across a range of formats.
Russia is discussing with the United States and the United Nations the possibility of creating additional corridors to deliver humanitarian relief to the besieged Syrian city of Aleppo, he added.
Three Reasons Why Russia Deployed Tu-22M3 Strategic Bombers to Iran
Russian Su-34 Jets Deployed in Iran Conduct Airstrikes Against Daesh in Syria
US to Pursue Russian Cooperation in Syria Despite Moscow Using Iran Airbase
Sergei Lavrov, Iran, Syria, Russia