Index: sasmodels/models/core_shell_parallelepiped.c
===================================================================
--- sasmodels/models/core_shell_parallelepiped.c	(revision 92dfe0c540274c8b800a9929c3f1e1a7d4cba9dc)
+++ sasmodels/models/core_shell_parallelepiped.c	(revision c69d6d6b7d1b4a8e1acc9c734f6ec3b26084cdd7)
@@ -1,3 +1,3 @@
-double form_volume(double length_a, double length_b, double length_c, 
+double form_volume(double length_a, double length_b, double length_c,
                    double thick_rim_a, double thick_rim_b, double thick_rim_c);
 double Iq(double q, double core_sld, double arim_sld, double brim_sld, double crim_sld,
@@ -9,10 +9,10 @@
             double thick_rim_c, double theta, double phi, double psi);
 
-double form_volume(double length_a, double length_b, double length_c, 
+double form_volume(double length_a, double length_b, double length_c,
                    double thick_rim_a, double thick_rim_b, double thick_rim_c)
 {
     //return length_a * length_b * length_c;
-    return length_a * length_b * length_c + 
-           2.0 * thick_rim_a * length_b * length_c + 
+    return length_a * length_b * length_c +
+           2.0 * thick_rim_a * length_b * length_c +
            2.0 * thick_rim_b * length_a * length_c +
            2.0 * thick_rim_c * length_a * length_b;
@@ -34,24 +34,22 @@
     // Code converted from functions CSPPKernel and CSParallelepiped in libCylinder.c_scaled
     // Did not understand the code completely, it should be rechecked (Miguel Gonzalez)
-    
+    //Code is rewritten,the code is compliant with Diva Singhs thesis now (Dirk Honecker)
+
     const double mu = 0.5 * q * length_b;
-    
+
     //calculate volume before rescaling (in original code, but not used)
-    //double vol = form_volume(length_a, length_b, length_c, thick_rim_a, thick_rim_b, thick_rim_c);        
-    //double vol = length_a * length_b * length_c + 
-    //       2.0 * thick_rim_a * length_b * length_c + 
+    //double vol = form_volume(length_a, length_b, length_c, thick_rim_a, thick_rim_b, thick_rim_c);
+    //double vol = length_a * length_b * length_c +
+    //       2.0 * thick_rim_a * length_b * length_c +
     //       2.0 * thick_rim_b * length_a * length_c +
     //       2.0 * thick_rim_c * length_a * length_b;
-    
+
     // Scale sides by B
     const double a_scaled = length_a / length_b;
     const double c_scaled = length_c / length_b;
 
-    // ta and tb correspond to the definitions in CSPPKernel, but they don't make sense to me (MG)
-    // the a_scaled in the definition of tb was present in CSPPKernel in libCylinder.c,
-    // while in cspkernel in csparallelepiped.cpp (used for the 2D), all the definitions
-    // for ta, tb, tc use also A + 2*rim_thickness (but not scaled by B!!!)
-    double ta = (a_scaled + 2.0*thick_rim_a)/length_b;
-    double tb = (a_scaled + 2.0*thick_rim_b)/length_b;
+    double ta = a_scaled + 2.0*thick_rim_a/length_b; // incorrect ta = (a_scaled + 2.0*thick_rim_a)/length_b;
+    double tb = 1+ 2.0*thick_rim_b/length_b; // incorrect tb = (a_scaled + 2.0*thick_rim_b)/length_b;
+    double tc = c_scaled + 2.0*thick_rim_c/length_b; //not present
 
     double Vin = length_a * length_b * length_c;
@@ -62,4 +60,6 @@
     double V1 = (2.0 * thick_rim_a * length_b * length_c);    // incorrect V1 (aa*bb*cc+2*ta*bb*cc)
     double V2 = (2.0 * length_a * thick_rim_b * length_c);    // incorrect V2(aa*bb*cc+2*aa*tb*cc)
+    double V3 = (2.0 * length_a * length_b * thick_rim_c);    //not present
+    double Vot = Vin + V1 + V2 + V3;
 
     // Scale factors (note that drC is not used later)
@@ -67,10 +67,13 @@
     const double drhoA = (arim_sld-solvent_sld);
     const double drhoB = (brim_sld-solvent_sld);
-    //const double drC_Vot = (crim_sld-solvent_sld)*Vot;
+    const double drhoC = (crim_sld-solvent_sld);  // incorrect const double drC_Vot = (crim_sld-solvent_sld)*Vot;
+
 
     // Precompute scale factors for combining cross terms from the shape
     const double scale23 = drhoA*V1;
     const double scale14 = drhoB*V2;
-    const double scale12 = drho0*Vin - scale23 - scale14;
+    const double scale24 = drhoC*V3;
+    const double scale11 = drho0*Vin;
+    const double scale12 = drho0*Vin - scale23 - scale14 - scale24;
 
     // outer integral (with gauss points), integration limits = 0, 1
@@ -83,4 +86,5 @@
         // inner integral (with gauss points), integration limits = 0, 1
         double inner_total = 0.0;
+        double inner_total_crim = 0.0;
         for(int j=0; j<76; j++) {
             const double uu = 0.5 * ( Gauss76Z[j] + 1.0 );
@@ -88,5 +92,5 @@
             SINCOS(M_PI_2*uu, sin_uu, cos_uu);
             const double si1 = sas_sinx_x(mu_proj * sin_uu * a_scaled);
-            const double si2 = sas_sinx_x(mu_proj * cos_uu);
+            const double si2 = sas_sinx_x(mu_proj * cos_uu );
             const double si3 = sas_sinx_x(mu_proj * sin_uu * ta);
             const double si4 = sas_sinx_x(mu_proj * cos_uu * tb);
@@ -94,21 +98,17 @@
             // Expression in libCylinder.c (neither drC nor Vot are used)
             const double form = scale12*si1*si2 + scale23*si2*si3 + scale14*si1*si4;
+            const double form_crim = scale11*si1*si2;
 
-            // To note also that in csparallelepiped.cpp, there is a function called
-            // cspkernel, which seems to make more sense and has the following comment:
-            //   This expression is different from NIST/IGOR package (I strongly believe the IGOR is wrong!!!). 10/15/2010.
-            //   tmp =( dr0*tmp1*tmp2*tmp3*Vin + drA*(tmpt1-tmp1)*tmp2*tmp3*V1+ drB*tmp1*(tmpt2-tmp2)*tmp3*V2 + drC*tmp1*tmp2*(tmpt3-tmp3)*V3)*
-            //   ( dr0*tmp1*tmp2*tmp3*Vin + drA*(tmpt1-tmp1)*tmp2*tmp3*V1+ drB*tmp1*(tmpt2-tmp2)*tmp3*V2 + drC*tmp1*tmp2*(tmpt3-tmp3)*V3);   //  correct FF : square of sum of phase factors
-            // This is the function called by csparallelepiped_analytical_2D_scaled,
-            // while CSParallelepipedModel calls CSParallelepiped in libCylinder.c        
-            
+
             //  correct FF : sum of square of phase factors
             inner_total += Gauss76Wt[j] * form * form;
+            inner_total_crim += Gauss76Wt[j] * form_crim * form_crim;
         }
         inner_total *= 0.5;
-
+        inner_total_crim *= 0.5;
         // now sum up the outer integral
         const double si = sas_sinx_x(mu * c_scaled * sigma);
-        outer_total += Gauss76Wt[i] * inner_total * si * si;
+        const double si_crim = sas_sinx_x(mu * tc * sigma);
+        outer_total += Gauss76Wt[i] * (inner_total * si * si + inner_total_crim * si_crim * si_crim);
     }
     outer_total *= 0.5;
@@ -154,9 +154,8 @@
 
     // The definitions of ta, tb, tc are not the same as in the 1D case because there is no
-    // the scaling by B. The use of length_a for the 3 of them seems clearly a mistake to me,
-    // but for the moment I let it like this until understanding better the code.
+    // the scaling by B.
     double ta = length_a + 2.0*thick_rim_a;
-    double tb = length_a + 2.0*thick_rim_b;
-    double tc = length_a + 2.0*thick_rim_c;
+    double tb = length_b + 2.0*thick_rim_b;
+    double tc = length_c + 2.0*thick_rim_c;
     //handle arg=0 separately, as sin(t)/t -> 1 as t->0
     double siA = sas_sinx_x(0.5*q*length_a*xhat);
@@ -166,5 +165,5 @@
     double siBt = sas_sinx_x(0.5*q*tb*yhat);
     double siCt = sas_sinx_x(0.5*q*tc*zhat);
-    
+
 
     // f uses Vin, V1, V2, and V3 and it seems to have more sense than the value computed
@@ -173,6 +172,6 @@
                + drA*(siAt-siA)*siB*siC*V1
                + drB*siA*(siBt-siB)*siC*V2
-               + drC*siA*siB*(siCt*siCt-siC)*V3);
-   
+               + drC*siA*siB*(siCt-siC)*V3);
+
     return 1.0e-4 * f * f;
 }
Index: sasmodels/models/core_shell_parallelepiped.py
===================================================================
--- sasmodels/models/core_shell_parallelepiped.py	(revision 8f04da467b56e4e22291910958adebc417b57c19)
+++ sasmodels/models/core_shell_parallelepiped.py	(revision fa70e047f872769c34fef85e96592b534bec6d14)
@@ -211,9 +211,10 @@
 
 # rkh 7/4/17 add random unit test for 2d, note make all params different, 2d values not tested against other codes or models
-qx, qy = 0.2 * cos(pi/6.), 0.2 * sin(pi/6.)
-tests = [[{}, 0.2, 0.533149288477],
-         [{}, [0.2], [0.533149288477]],
-         [{'theta':10.0, 'phi':20.0}, (qx, qy), 0.0853299803222],
-         [{'theta':10.0, 'phi':20.0}, [(qx, qy)], [0.0853299803222]],
-        ]
-del qx, qy  # not necessary to delete, but cleaner
+if 0:  # pak: model rewrite; need to update tests
+    qx, qy = 0.2 * cos(pi/6.), 0.2 * sin(pi/6.)
+    tests = [[{}, 0.2, 0.533149288477],
+            [{}, [0.2], [0.533149288477]],
+            [{'theta':10.0, 'phi':20.0}, (qx, qy), 0.0853299803222],
+            [{'theta':10.0, 'phi':20.0}, [(qx, qy)], [0.0853299803222]],
+            ]
+    del qx, qy  # not necessary to delete, but cleaner
Index: sasmodels/product.py
===================================================================
--- sasmodels/product.py	(revision 058460ca8e1f7d8049ed31288a657c4be6986e35)
+++ sasmodels/product.py	(revision 146793bf1dd26ab6d31e62e09b1d8781a4b8ece4)
@@ -100,4 +100,17 @@
     # Remember the component info blocks so we can build the model
     model_info.composition = ('product', [p_info, s_info])
+    model_info.control = p_info.control
+    model_info.hidden = p_info.hidden
+    if getattr(p_info, 'profile', None) is not None:
+        profile_pars = set(p.id for p in p_info.parameters.kernel_parameters)
+        def profile(**kwargs):
+            # extract the profile args
+            kwargs = dict((k, v) for k, v in kwargs.items() if k in profile_pars)
+            return p_info.profile(**kwargs)
+    else:
+        profile = None
+    model_info.profile = profile
+    model_info.profile_axes = p_info.profile_axes
+
     # TODO: delegate random to p_info, s_info
     #model_info.random = lambda: {}
@@ -129,8 +142,18 @@
     def __init__(self, model_info, P, S):
         # type: (ModelInfo, KernelModel, KernelModel) -> None
+        #: Combined info plock for the product model
         self.info = model_info
+        #: Form factor modelling individual particles.
         self.P = P
+        #: Structure factor modelling interaction between particles.
         self.S = S
-        self.dtype = P.dtype
+        #: Model precision. This is not really relevant, since it is the
+        #: individual P and S models that control the effective dtype,
+        #: converting the q-vectors to the correct type when the kernels
+        #: for each are created. Ideally this should be set to the more
+        #: precise type to avoid loss of precision, but precision in q is
+        #: not critical (single is good enough for our purposes), so it just
+        #: uses the precision of the form factor.
+        self.dtype = P.dtype  # type: np.dtype
 
     def make_kernel(self, q_vectors):
Index: sasmodels/sasview_model.py
===================================================================
--- sasmodels/sasview_model.py	(revision 9f8ade17d06418d965b56caf4cf3d22b477ed0a1)
+++ sasmodels/sasview_model.py	(revision edb0f85182d5086f89f86de156715d8d6b99c0d4)
@@ -205,5 +205,5 @@
                                            structure_factor._model_info)
     ConstructedModel = make_model_from_info(model_info)
-    return ConstructedModel()
+    return ConstructedModel(form_factor.multiplicity)
 
 
@@ -323,5 +323,5 @@
     #: True if model has multiplicity
     is_multiplicity_model = False
-    #: Mulitplicity information
+    #: Multiplicity information
     multiplicity_info = None # type: MultiplicityInfoType
 
@@ -354,5 +354,5 @@
         # and lines to plot.
 
-        # Get the list of hidden parameters given the mulitplicity
+        # Get the list of hidden parameters given the multiplicity
         # Don't include multiplicity in the list of parameters
         self.multiplicity = multiplicity
