0
$\begingroup$

This looks long and complicated, but it's really not. I just tried to pose the problem well.

I have to solve a relatively complicated system of equations that has 2 variables and 3 parameters.

I start with some simplifications to make the equation readable:

Clear[z, F2, g, a]
z = 1;
aa[a_, aNL_] := a - aNL
gg[g_, gNL_] := Sqrt[g^2 + gNL^2]

These equations feed into the following system of two equations with two variables (aNL,gNL) which also depend on three input parameters (a,F2,g). The system of equations is defined as SLNS2 below.

SLNS2[aVal_, F2Val_, gVal_] := 
 NSolve[{aNL == (2 z + 1)/2 F2 (
      1 + (aa[a, aNL] - gNL)^2 + 
       gg[g, gNL]^2)/((1 + gg[g, gNL]^2 - aa[a, aNL]^2)^2 + 
       4 aa[a, aNL]^2), 
    gNL == (2 z - 1)/2 F2 (
      1 + (aa[a, aNL] - gNL)^2 - 
       g^2)/((1 + gg[g, gNL]^2 - aa[a, aNL]^2)^2 + 
       4 aa[a, aNL]^2)} /. {a -> aVal, F2 -> F2Val, g -> gVal}, {aNL, 
   gNL}, Reals]

Note, that in order to explore the dependence of the solutions to specific values of input parameters I used /. {a -> aVal, F2 -> F2Val, g -> gVal}.

For certain input parameters the system of equations is single valued in (aNL,gNL):

SLNS2[2, 30, 0.01]

For other input parameter values, the system is multivalued with up to 5 unique solutions:

SLNS2[14.5, 30, 0.01]

The next goal was building functions (or at least curves) for each variable against the input parameter a, leaving the other two parameters (F2,g) as input parameters.

Single-valued Solutions

To construct these curves I made a 2-column list for both "aNL vs a" and "gNL vs a" using LISTaNL and LISTgNL respectively.

aMIN1 = -30;
aMAX1 = +10;

LISTaNL[F2Val_, gVal_, aSTEP_] := 
 Table[{aVal, SLNS2[aVal, F2Val, gVal][[1]][[1]][[2]]}, {aVal, aMIN1, 
   aMAX1, aSTEP}]

LISTgNL[F2Val_, gVal_, aSTEP_] := 
 Table[{aVal, SLNS2[aVal, F2Val, gVal][[1]][[2]][[2]]}, {aVal, aMIN1, 
   aMAX1, aSTEP}]

In the above functions the [[1]][[1]][[2]] serve to pick out the numerical value of aNL or gNL in each solution. To see how this works run the code below.

SLNS2[-20, 30, 1]
SLNS2[-20, 30, 1][[1]]
SLNS2[-20, 30, 1][[1]][[1]]
SLNS2[-20, 30, 1][[1]][[1]][[2]] (*isolate aNL value*)
SLNS2[-20, 30, 1][[1]][[2]][[2]] (*isolate gNL value*)

Sample output is below

aNLsingle = LISTaNL[30, 1, 2];
gNLsingle = LISTgNL[30, 1, 2];

ListPlot[{aNLsingle, gNLsingle}, PlotRange -> {{-30, 60}, {-2, 60}}, 
 PlotStyle -> {Red, Blue}, Axes -> False, Frame -> True, 
 FrameLabel -> {"a", "aNL or gNL"}, PlotStyle -> Red, 
 LabelStyle -> Directive[Black, fontsize, FontFamily -> "Arial"], 
 PlotLabel -> 
  Style["Sample single-valued solutions", fontsize, Bold, Black], 
 PlotLegends -> 
  Placed[LineLegend[{"aNL", "gNL"},(*LegendFunction\[Rule]"Frame",*)
    LegendMarkerSize -> 15, 
    LabelStyle -> Directive[FontFamily -> "Arial", 16], 
    LegendLayout -> "Column"], {0.26, 0.575}]]

Multi-valued Solutions

All of the important information from these curves is in the multi-valued regions. The simple approach above fails when it's multivalued because it only grabs the first solution.

My current (silly) method for dealing with this is to:

  1. List item Construct multiple curves for each of the 5 solutions
  2. List item Delete non-numerical entries with Select[,#[[2]]>0&]
  3. List item Join the 5 solutions together into one list.

(Note that to see the multivalued solutions I've increased the range of a values)

aMIN2 = -30;
aMAX2 = 40;

LISTaNLi[F2Val_, gVal_, aSTEP_, i_] := 
 Select[Table[{aVal, SLNS2[aVal, F2Val, gVal][[i]][[1]][[2]]}, {aVal, 
    aMIN2, aMAX2, aSTEP}], #[[2]] > 0 &]
LISTgNLi[F2Val_, gVal_, aSTEP_, i_] := 
 Select[Table[{aVal, SLNS2[aVal, F2Val, gVal][[i]][[2]][[2]]}, {aVal, 
    aMIN2, aMAX2, aSTEP}], #[[2]] > 0 &]

Joining the lists together

LISTaNLall[F2Val_, gVal_, aSTEP_] := 
 Join[LISTaNLi[F2Val, gVal, aSTEP, 1], 
  LISTaNLi[F2Val, gVal, aSTEP, 2], LISTaNLi[F2Val, gVal, aSTEP, 3], 
  LISTaNLi[F2Val, gVal, aSTEP, 4], LISTaNLi[F2Val, gVal, aSTEP, 5]]

LISTgNLall[F2Val_, gVal_, aSTEP_] := 
 Join[LISTgNLi[F2Val, gVal, aSTEP, 1], 
  LISTgNLi[F2Val, gVal, aSTEP, 2], LISTgNLi[F2Val, gVal, aSTEP, 3], 
  LISTgNLi[F2Val, gVal, aSTEP, 4], LISTgNLi[F2Val, gVal, aSTEP, 5]]

And here's a sample plot of the output (this will probably take about 60s to run. If it's too slow, increase aSTEP to something like 5):

aNLmulti = LISTaNLall[30, 1, 0.5];
gNLmulti = LISTgNLall[30, 1, 0.5];

ListPlot[{aNLmulti, gNLmulti}, PlotRange -> {{-30, 60}, {-2, 60}}, 
 PlotStyle -> {Red, Blue}, Axes -> False, Frame -> True, 
 FrameLabel -> {"a", "aNL or gNL"}, PlotStyle -> Red, 
 LabelStyle -> Directive[Black, fontsize, FontFamily -> "Arial"], 
 PlotLabel -> 
  Style["Sample multi-valued solutions", fontsize, Bold, Black], 
 PlotLegends -> 
  Placed[LineLegend[{"aNL", "gNL"},(*LegendFunction\[Rule]"Frame",*)
    LegendMarkerSize -> 15, 
    LabelStyle -> Directive[FontFamily -> "Arial", 16], 
    LegendLayout -> "Column"], {0.26, 0.575}]]

(FYI, don't worry about the errors for now, it's just complaining about things like the 2nd solution doesn't exist in all regions. These datapoints are removed with Select)

The Problem

My approach takes way too much computation time. In my current method, I have to solve for all the solutions a redundant five times (because I just take the relevant element for the i^th solution). Is there a more elegant way to do this so that my computation times aren't 5 times as long as they have to be?

**How do I get mathematica to not output data as a 'nested list' and just output all of the solutions as a simple list in the first place? **

Bonus Questions

Interpolation fails when applied LISTaNLall[F2Val_, gVal_, aSTEP_]. Is there some way to construct an interpolating for multivalued curves so that you can evaluate at arbitrary points (within reason)?

ListLinePLot is a disaster for the same reason. Is there a way to tell mathematica how to follow the curves (without ordering the lists by hand)? What would this even be called? Any relevant search terms?

Thanks!

$\endgroup$
2
  • $\begingroup$ Let me point out that you could much more simply use something like Plot[aNL /. SLNS2[aVal, 30, 1], {aVal, aMIN1, aMAX1}] and get a good plot much more succinctly, while taking advantage of Plot's adaptive sampling capabilities. Consider also that, instead of the fragile SLNS2[-20, 30, 1][[1]][[2]][[2]] (which, by the way, you could write as SLNS2[-20, 30, 1][[1, 2, 2]]), you should really try to use something like gNL /. SLNS2[-20, 30, 1]. $\endgroup$ – MarcoB Apr 22 '20 at 3:35
  • $\begingroup$ @MarcoB Thanks for the tip. The nomenclature is definitely cleaned up but it still has the fundamental problem of missing the multivalued regions. aNLmultiCOARSE = LISTaNLall[30, 1, 2]; Show[ ListPlot[aNLmultiCOARSE, PlotStyle -> {Red, PointSize[0.01]}, PlotRange -> {{-32, 52}, {-1, 59}}, Frame -> True], Plot[aNL /. SLNS2[aVal, 30, 1], {aVal, -30, 59}, PlotStyle -> Blue, PlotRange -> {{-32, 52}, {-1, 59}}] ] $\endgroup$ – Drotar Apr 22 '20 at 16:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.